001/*
002 * Copyright (C) 2017 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.primitives;
016
017import static com.google.common.base.Preconditions.checkArgument;
018
019import com.google.common.annotations.Beta;
020import com.google.common.annotations.GwtCompatible;
021import com.google.common.base.Preconditions;
022import com.google.errorprone.annotations.CanIgnoreReturnValue;
023import com.google.errorprone.annotations.CheckReturnValue;
024import com.google.errorprone.annotations.Immutable;
025import java.io.Serializable;
026import java.util.AbstractList;
027import java.util.Arrays;
028import java.util.Collection;
029import java.util.List;
030import java.util.RandomAccess;
031import org.checkerframework.checker.nullness.compatqual.NullableDecl;
032
033/**
034 * An immutable array of {@code long} values, with an API resembling {@link List}.
035 *
036 * <p>Advantages compared to {@code long[]}:
037 *
038 * <ul>
039 *   <li>All the many well-known advantages of immutability (read <i>Effective Java</i>, third
040 *       edition, Item 17).
041 *   <li>Has the value-based (not identity-based) {@link #equals}, {@link #hashCode}, and {@link
042 *       #toString} behavior you expect.
043 *   <li>Offers useful operations beyond just {@code get} and {@code length}, so you don't have to
044 *       hunt through classes like {@link Arrays} and {@link Longs} for them.
045 *   <li>Supports a copy-free {@link #subArray} view, so methods that accept this type don't need to
046 *       add overloads that accept start and end indexes.
047 *   <li>Access to all collection-based utilities via {@link #asList} (though at the cost of
048 *       allocating garbage).
049 * </ul>
050 *
051 * <p>Disadvantages compared to {@code long[]}:
052 *
053 * <ul>
054 *   <li>Memory footprint has a fixed overhead (about 24 bytes per instance).
055 *   <li><i>Some</i> construction use cases force the data to be copied (though several construction
056 *       APIs are offered that don't).
057 *   <li>Can't be passed directly to methods that expect {@code long[]} (though the most common
058 *       utilities do have replacements here).
059 *   <li>Dependency on {@code com.google.common} / Guava.
060 * </ul>
061 *
062 * <p>Advantages compared to {@link com.google.common.collect.ImmutableList ImmutableList}{@code
063 * <Long>}:
064 *
065 * <ul>
066 *   <li>Improved memory compactness and locality.
067 *   <li>Can be queried without allocating garbage.
068 * </ul>
069 *
070 * <p>Disadvantages compared to {@code ImmutableList<Long>}:
071 *
072 * <ul>
073 *   <li>Can't be passed directly to methods that expect {@code Iterable}, {@code Collection}, or
074 *       {@code List} (though the most common utilities do have replacements here, and there is a
075 *       lazy {@link #asList} view).
076 * </ul>
077 *
078 * @since 22.0
079 */
080@Beta
081@GwtCompatible
082@Immutable
083public final class ImmutableLongArray implements Serializable {
084  private static final ImmutableLongArray EMPTY = new ImmutableLongArray(new long[0]);
085
086  /** Returns the empty array. */
087  public static ImmutableLongArray of() {
088    return EMPTY;
089  }
090
091  /** Returns an immutable array containing a single value. */
092  public static ImmutableLongArray of(long e0) {
093    return new ImmutableLongArray(new long[] {e0});
094  }
095
096  /** Returns an immutable array containing the given values, in order. */
097  public static ImmutableLongArray of(long e0, long e1) {
098    return new ImmutableLongArray(new long[] {e0, e1});
099  }
100
101  /** Returns an immutable array containing the given values, in order. */
102  public static ImmutableLongArray of(long e0, long e1, long e2) {
103    return new ImmutableLongArray(new long[] {e0, e1, e2});
104  }
105
106  /** Returns an immutable array containing the given values, in order. */
107  public static ImmutableLongArray of(long e0, long e1, long e2, long e3) {
108    return new ImmutableLongArray(new long[] {e0, e1, e2, e3});
109  }
110
111  /** Returns an immutable array containing the given values, in order. */
112  public static ImmutableLongArray of(long e0, long e1, long e2, long e3, long e4) {
113    return new ImmutableLongArray(new long[] {e0, e1, e2, e3, e4});
114  }
115
116  /** Returns an immutable array containing the given values, in order. */
117  public static ImmutableLongArray of(long e0, long e1, long e2, long e3, long e4, long e5) {
118    return new ImmutableLongArray(new long[] {e0, e1, e2, e3, e4, e5});
119  }
120
121  // TODO(kevinb): go up to 11?
122
123  /**
124   * Returns an immutable array containing the given values, in order.
125   *
126   * <p>The array {@code rest} must not be longer than {@code Integer.MAX_VALUE - 1}.
127   */
128  // Use (first, rest) so that `of(someLongArray)` won't compile (they should use copyOf), which is
129  // okay since we have to copy the just-created array anyway.
130  public static ImmutableLongArray of(long first, long... rest) {
131    checkArgument(
132        rest.length <= Integer.MAX_VALUE - 1, "the total number of elements must fit in an int");
133    long[] array = new long[rest.length + 1];
134    array[0] = first;
135    System.arraycopy(rest, 0, array, 1, rest.length);
136    return new ImmutableLongArray(array);
137  }
138
139  /** Returns an immutable array containing the given values, in order. */
140  public static ImmutableLongArray copyOf(long[] values) {
141    return values.length == 0
142        ? EMPTY
143        : new ImmutableLongArray(Arrays.copyOf(values, values.length));
144  }
145
146  /** Returns an immutable array containing the given values, in order. */
147  public static ImmutableLongArray copyOf(Collection<Long> values) {
148    return values.isEmpty() ? EMPTY : new ImmutableLongArray(Longs.toArray(values));
149  }
150
151  /**
152   * Returns an immutable array containing the given values, in order.
153   *
154   * <p><b>Performance note:</b> this method delegates to {@link #copyOf(Collection)} if {@code
155   * values} is a {@link Collection}. Otherwise it creates a {@link #builder} and uses {@link
156   * Builder#addAll(Iterable)}, with all the performance implications associated with that.
157   */
158  public static ImmutableLongArray copyOf(Iterable<Long> values) {
159    if (values instanceof Collection) {
160      return copyOf((Collection<Long>) values);
161    }
162    return builder().addAll(values).build();
163  }
164
165  /**
166   * Returns a new, empty builder for {@link ImmutableLongArray} instances, sized to hold up to
167   * {@code initialCapacity} values without resizing. The returned builder is not thread-safe.
168   *
169   * <p><b>Performance note:</b> When feasible, {@code initialCapacity} should be the exact number
170   * of values that will be added, if that knowledge is readily available. It is better to guess a
171   * value slightly too high than slightly too low. If the value is not exact, the {@link
172   * ImmutableLongArray} that is built will very likely occupy more memory than strictly necessary;
173   * to trim memory usage, build using {@code builder.build().trimmed()}.
174   */
175  public static Builder builder(int initialCapacity) {
176    checkArgument(initialCapacity >= 0, "Invalid initialCapacity: %s", initialCapacity);
177    return new Builder(initialCapacity);
178  }
179
180  /**
181   * Returns a new, empty builder for {@link ImmutableLongArray} instances, with a default initial
182   * capacity. The returned builder is not thread-safe.
183   *
184   * <p><b>Performance note:</b> The {@link ImmutableLongArray} that is built will very likely
185   * occupy more memory than necessary; to trim memory usage, build using {@code
186   * builder.build().trimmed()}.
187   */
188  public static Builder builder() {
189    return new Builder(10);
190  }
191
192  /**
193   * A builder for {@link ImmutableLongArray} instances; obtained using {@link
194   * ImmutableLongArray#builder}.
195   */
196  @CanIgnoreReturnValue
197  public static final class Builder {
198    private long[] array;
199    private int count = 0; // <= array.length
200
201    Builder(int initialCapacity) {
202      array = new long[initialCapacity];
203    }
204
205    /**
206     * Appends {@code value} to the end of the values the built {@link ImmutableLongArray} will
207     * contain.
208     */
209    public Builder add(long value) {
210      ensureRoomFor(1);
211      array[count] = value;
212      count += 1;
213      return this;
214    }
215
216    /**
217     * Appends {@code values}, in order, to the end of the values the built {@link
218     * ImmutableLongArray} will contain.
219     */
220    public Builder addAll(long[] values) {
221      ensureRoomFor(values.length);
222      System.arraycopy(values, 0, array, count, values.length);
223      count += values.length;
224      return this;
225    }
226
227    /**
228     * Appends {@code values}, in order, to the end of the values the built {@link
229     * ImmutableLongArray} will contain.
230     */
231    public Builder addAll(Iterable<Long> values) {
232      if (values instanceof Collection) {
233        return addAll((Collection<Long>) values);
234      }
235      for (Long value : values) {
236        add(value);
237      }
238      return this;
239    }
240
241    /**
242     * Appends {@code values}, in order, to the end of the values the built {@link
243     * ImmutableLongArray} will contain.
244     */
245    public Builder addAll(Collection<Long> values) {
246      ensureRoomFor(values.size());
247      for (Long value : values) {
248        array[count++] = value;
249      }
250      return this;
251    }
252
253    /**
254     * Appends {@code values}, in order, to the end of the values the built {@link
255     * ImmutableLongArray} will contain.
256     */
257    public Builder addAll(ImmutableLongArray values) {
258      ensureRoomFor(values.length());
259      System.arraycopy(values.array, values.start, array, count, values.length());
260      count += values.length();
261      return this;
262    }
263
264    private void ensureRoomFor(int numberToAdd) {
265      int newCount = count + numberToAdd; // TODO(kevinb): check overflow now?
266      if (newCount > array.length) {
267        long[] newArray = new long[expandedCapacity(array.length, newCount)];
268        System.arraycopy(array, 0, newArray, 0, count);
269        this.array = newArray;
270      }
271    }
272
273    // Unfortunately this is pasted from ImmutableCollection.Builder.
274    private static int expandedCapacity(int oldCapacity, int minCapacity) {
275      if (minCapacity < 0) {
276        throw new AssertionError("cannot store more than MAX_VALUE elements");
277      }
278      // careful of overflow!
279      int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
280      if (newCapacity < minCapacity) {
281        newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
282      }
283      if (newCapacity < 0) {
284        newCapacity = Integer.MAX_VALUE; // guaranteed to be >= newCapacity
285      }
286      return newCapacity;
287    }
288
289    /**
290     * Returns a new immutable array. The builder can continue to be used after this call, to append
291     * more values and build again.
292     *
293     * <p><b>Performance note:</b> the returned array is backed by the same array as the builder, so
294     * no data is copied as part of this step, but this may occupy more memory than strictly
295     * necessary. To copy the data to a right-sized backing array, use {@code .build().trimmed()}.
296     */
297    @CheckReturnValue
298    public ImmutableLongArray build() {
299      return count == 0 ? EMPTY : new ImmutableLongArray(array, 0, count);
300    }
301  }
302
303  // Instance stuff here
304
305  // The array is never mutated after storing in this field and the construction strategies ensure
306  // it doesn't escape this class
307  @SuppressWarnings("Immutable")
308  private final long[] array;
309
310  /*
311   * TODO(kevinb): evaluate the trade-offs of going bimorphic to save these two fields from most
312   * instances. Note that the instances that would get smaller are the right set to care about
313   * optimizing, because the rest have the option of calling `trimmed`.
314   */
315
316  private final transient int start; // it happens that we only serialize instances where this is 0
317  private final int end; // exclusive
318
319  private ImmutableLongArray(long[] array) {
320    this(array, 0, array.length);
321  }
322
323  private ImmutableLongArray(long[] array, int start, int end) {
324    this.array = array;
325    this.start = start;
326    this.end = end;
327  }
328
329  /** Returns the number of values in this array. */
330  public int length() {
331    return end - start;
332  }
333
334  /** Returns {@code true} if there are no values in this array ({@link #length} is zero). */
335  public boolean isEmpty() {
336    return end == start;
337  }
338
339  /**
340   * Returns the {@code long} value present at the given index.
341   *
342   * @throws IndexOutOfBoundsException if {@code index} is negative, or greater than or equal to
343   *     {@link #length}
344   */
345  public long get(int index) {
346    Preconditions.checkElementIndex(index, length());
347    return array[start + index];
348  }
349
350  /**
351   * Returns the smallest index for which {@link #get} returns {@code target}, or {@code -1} if no
352   * such index exists. Equivalent to {@code asList().indexOf(target)}.
353   */
354  public int indexOf(long target) {
355    for (int i = start; i < end; i++) {
356      if (array[i] == target) {
357        return i - start;
358      }
359    }
360    return -1;
361  }
362
363  /**
364   * Returns the largest index for which {@link #get} returns {@code target}, or {@code -1} if no
365   * such index exists. Equivalent to {@code asList().lastIndexOf(target)}.
366   */
367  public int lastIndexOf(long target) {
368    for (int i = end - 1; i >= start; i--) {
369      if (array[i] == target) {
370        return i - start;
371      }
372    }
373    return -1;
374  }
375
376  /**
377   * Returns {@code true} if {@code target} is present at any index in this array. Equivalent to
378   * {@code asList().contains(target)}.
379   */
380  public boolean contains(long target) {
381    return indexOf(target) >= 0;
382  }
383
384  /** Returns a new, mutable copy of this array's values, as a primitive {@code long[]}. */
385  public long[] toArray() {
386    return Arrays.copyOfRange(array, start, end);
387  }
388
389  /**
390   * Returns a new immutable array containing the values in the specified range.
391   *
392   * <p><b>Performance note:</b> The returned array has the same full memory footprint as this one
393   * does (no actual copying is performed). To reduce memory usage, use {@code subArray(start,
394   * end).trimmed()}.
395   */
396  public ImmutableLongArray subArray(int startIndex, int endIndex) {
397    Preconditions.checkPositionIndexes(startIndex, endIndex, length());
398    return startIndex == endIndex
399        ? EMPTY
400        : new ImmutableLongArray(array, start + startIndex, start + endIndex);
401  }
402
403  /**
404   * Returns an immutable <i>view</i> of this array's values as a {@code List}; note that {@code
405   * long} values are boxed into {@link Long} instances on demand, which can be very expensive. The
406   * returned list should be used once and discarded. For any usages beyond that, pass the returned
407   * list to {@link com.google.common.collect.ImmutableList#copyOf(Collection) ImmutableList.copyOf}
408   * and use that list instead.
409   */
410  public List<Long> asList() {
411    /*
412     * Typically we cache this kind of thing, but much repeated use of this view is a performance
413     * anti-pattern anyway. If we cache, then everyone pays a price in memory footprint even if
414     * they never use this method.
415     */
416    return new AsList(this);
417  }
418
419  static class AsList extends AbstractList<Long> implements RandomAccess, Serializable {
420    private final ImmutableLongArray parent;
421
422    private AsList(ImmutableLongArray parent) {
423      this.parent = parent;
424    }
425
426    // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, mutations
427
428    @Override
429    public int size() {
430      return parent.length();
431    }
432
433    @Override
434    public Long get(int index) {
435      return parent.get(index);
436    }
437
438    @Override
439    public boolean contains(Object target) {
440      return indexOf(target) >= 0;
441    }
442
443    @Override
444    public int indexOf(Object target) {
445      return target instanceof Long ? parent.indexOf((Long) target) : -1;
446    }
447
448    @Override
449    public int lastIndexOf(Object target) {
450      return target instanceof Long ? parent.lastIndexOf((Long) target) : -1;
451    }
452
453    @Override
454    public List<Long> subList(int fromIndex, int toIndex) {
455      return parent.subArray(fromIndex, toIndex).asList();
456    }
457
458    @Override
459    public boolean equals(@NullableDecl Object object) {
460      if (object instanceof AsList) {
461        AsList that = (AsList) object;
462        return this.parent.equals(that.parent);
463      }
464      // We could delegate to super now but it would still box too much
465      if (!(object instanceof List)) {
466        return false;
467      }
468      List<?> that = (List<?>) object;
469      if (this.size() != that.size()) {
470        return false;
471      }
472      int i = parent.start;
473      // Since `that` is very likely RandomAccess we could avoid allocating this iterator...
474      for (Object element : that) {
475        if (!(element instanceof Long) || parent.array[i++] != (Long) element) {
476          return false;
477        }
478      }
479      return true;
480    }
481
482    // Because we happen to use the same formula. If that changes, just don't override this.
483    @Override
484    public int hashCode() {
485      return parent.hashCode();
486    }
487
488    @Override
489    public String toString() {
490      return parent.toString();
491    }
492  }
493
494  /**
495   * Returns {@code true} if {@code object} is an {@code ImmutableLongArray} containing the same
496   * values as this one, in the same order.
497   */
498  @Override
499  public boolean equals(@NullableDecl Object object) {
500    if (object == this) {
501      return true;
502    }
503    if (!(object instanceof ImmutableLongArray)) {
504      return false;
505    }
506    ImmutableLongArray that = (ImmutableLongArray) object;
507    if (this.length() != that.length()) {
508      return false;
509    }
510    for (int i = 0; i < length(); i++) {
511      if (this.get(i) != that.get(i)) {
512        return false;
513      }
514    }
515    return true;
516  }
517
518  /** Returns an unspecified hash code for the contents of this immutable array. */
519  @Override
520  public int hashCode() {
521    int hash = 1;
522    for (int i = start; i < end; i++) {
523      hash *= 31;
524      hash += Longs.hashCode(array[i]);
525    }
526    return hash;
527  }
528
529  /**
530   * Returns a string representation of this array in the same form as {@link
531   * Arrays#toString(long[])}, for example {@code "[1, 2, 3]"}.
532   */
533  @Override
534  public String toString() {
535    if (isEmpty()) {
536      return "[]";
537    }
538    StringBuilder builder = new StringBuilder(length() * 5); // rough estimate is fine
539    builder.append('[').append(array[start]);
540
541    for (int i = start + 1; i < end; i++) {
542      builder.append(", ").append(array[i]);
543    }
544    builder.append(']');
545    return builder.toString();
546  }
547
548  /**
549   * Returns an immutable array containing the same values as {@code this} array. This is logically
550   * a no-op, and in some circumstances {@code this} itself is returned. However, if this instance
551   * is a {@link #subArray} view of a larger array, this method will copy only the appropriate range
552   * of values, resulting in an equivalent array with a smaller memory footprint.
553   */
554  public ImmutableLongArray trimmed() {
555    return isPartialView() ? new ImmutableLongArray(toArray()) : this;
556  }
557
558  private boolean isPartialView() {
559    return start > 0 || end < array.length;
560  }
561
562  Object writeReplace() {
563    return trimmed();
564  }
565
566  Object readResolve() {
567    return isEmpty() ? EMPTY : this;
568  }
569}