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