001/*
002 * Copyright (C) 2008 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;
018import static com.google.common.base.Preconditions.checkElementIndex;
019import static com.google.common.base.Preconditions.checkNotNull;
020import static com.google.common.base.Preconditions.checkPositionIndexes;
021
022import com.google.common.annotations.GwtCompatible;
023import com.google.common.annotations.GwtIncompatible;
024import com.google.common.base.Converter;
025import com.google.errorprone.annotations.InlineMe;
026import java.io.Serializable;
027import java.util.AbstractList;
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.Collections;
031import java.util.Comparator;
032import java.util.List;
033import java.util.RandomAccess;
034import org.jspecify.annotations.Nullable;
035
036/**
037 * Static utility methods pertaining to {@code short} primitives, that are not already found in
038 * either {@link Short} or {@link Arrays}.
039 *
040 * <p>See the Guava User Guide article on <a
041 * href="https://github.com/google/guava/wiki/PrimitivesExplained">primitive utilities</a>.
042 *
043 * @author Kevin Bourrillion
044 * @since 1.0
045 */
046@GwtCompatible(emulated = true)
047public final class Shorts extends ShortsMethodsForWeb {
048  private Shorts() {}
049
050  /**
051   * The number of bytes required to represent a primitive {@code short} value.
052   *
053   * <p><b>Java 8+ users:</b> use {@link Short#BYTES} instead.
054   */
055  public static final int BYTES = Short.SIZE / Byte.SIZE;
056
057  /**
058   * The largest power of two that can be represented as a {@code short}.
059   *
060   * @since 10.0
061   */
062  public static final short MAX_POWER_OF_TWO = 1 << (Short.SIZE - 2);
063
064  /**
065   * Returns a hash code for {@code value}; equal to the result of invoking {@code ((Short)
066   * value).hashCode()}.
067   *
068   * <p><b>Java 8+ users:</b> use {@link Short#hashCode(short)} instead.
069   *
070   * @param value a primitive {@code short} value
071   * @return a hash code for the value
072   */
073  public static int hashCode(short value) {
074    return value;
075  }
076
077  /**
078   * Returns the {@code short} value that is equal to {@code value}, if possible.
079   *
080   * @param value any value in the range of the {@code short} type
081   * @return the {@code short} value that equals {@code value}
082   * @throws IllegalArgumentException if {@code value} is greater than {@link Short#MAX_VALUE} or
083   *     less than {@link Short#MIN_VALUE}
084   */
085  public static short checkedCast(long value) {
086    short result = (short) value;
087    checkArgument(result == value, "Out of range: %s", value);
088    return result;
089  }
090
091  /**
092   * Returns the {@code short} nearest in value to {@code value}.
093   *
094   * @param value any {@code long} value
095   * @return the same value cast to {@code short} if it is in the range of the {@code short} type,
096   *     {@link Short#MAX_VALUE} if it is too large, or {@link Short#MIN_VALUE} if it is too small
097   */
098  public static short saturatedCast(long value) {
099    if (value > Short.MAX_VALUE) {
100      return Short.MAX_VALUE;
101    }
102    if (value < Short.MIN_VALUE) {
103      return Short.MIN_VALUE;
104    }
105    return (short) value;
106  }
107
108  /**
109   * Compares the two specified {@code short} values. The sign of the value returned is the same as
110   * that of {@code ((Short) a).compareTo(b)}.
111   *
112   * <p><b>Note:</b> this method is now unnecessary and should be treated as deprecated; use the
113   * equivalent {@link Short#compare} method instead.
114   *
115   * @param a the first {@code short} to compare
116   * @param b the second {@code short} to compare
117   * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
118   *     greater than {@code b}; or zero if they are equal
119   */
120  @InlineMe(replacement = "Short.compare(a, b)")
121  public static int compare(short a, short b) {
122    return Short.compare(a, b);
123  }
124
125  /**
126   * Returns {@code true} if {@code target} is present as an element anywhere in {@code array}.
127   *
128   * @param array an array of {@code short} values, possibly empty
129   * @param target a primitive {@code short} value
130   * @return {@code true} if {@code array[i] == target} for some value of {@code i}
131   */
132  public static boolean contains(short[] array, short target) {
133    for (short value : array) {
134      if (value == target) {
135        return true;
136      }
137    }
138    return false;
139  }
140
141  /**
142   * Returns the index of the first appearance of the value {@code target} in {@code array}.
143   *
144   * @param array an array of {@code short} values, possibly empty
145   * @param target a primitive {@code short} value
146   * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no
147   *     such index exists.
148   */
149  public static int indexOf(short[] array, short target) {
150    return indexOf(array, target, 0, array.length);
151  }
152
153  // TODO(kevinb): consider making this public
154  private static int indexOf(short[] array, short target, int start, int end) {
155    for (int i = start; i < end; i++) {
156      if (array[i] == target) {
157        return i;
158      }
159    }
160    return -1;
161  }
162
163  /**
164   * Returns the start position of the first occurrence of the specified {@code target} within
165   * {@code array}, or {@code -1} if there is no such occurrence.
166   *
167   * <p>More formally, returns the lowest index {@code i} such that {@code Arrays.copyOfRange(array,
168   * i, i + target.length)} contains exactly the same elements as {@code target}.
169   *
170   * @param array the array to search for the sequence {@code target}
171   * @param target the array to search for as a sub-sequence of {@code array}
172   */
173  public static int indexOf(short[] array, short[] target) {
174    checkNotNull(array, "array");
175    checkNotNull(target, "target");
176    if (target.length == 0) {
177      return 0;
178    }
179
180    outer:
181    for (int i = 0; i < array.length - target.length + 1; i++) {
182      for (int j = 0; j < target.length; j++) {
183        if (array[i + j] != target[j]) {
184          continue outer;
185        }
186      }
187      return i;
188    }
189    return -1;
190  }
191
192  /**
193   * Returns the index of the last appearance of the value {@code target} in {@code array}.
194   *
195   * @param array an array of {@code short} values, possibly empty
196   * @param target a primitive {@code short} value
197   * @return the greatest index {@code i} for which {@code array[i] == target}, or {@code -1} if no
198   *     such index exists.
199   */
200  public static int lastIndexOf(short[] array, short target) {
201    return lastIndexOf(array, target, 0, array.length);
202  }
203
204  // TODO(kevinb): consider making this public
205  private static int lastIndexOf(short[] array, short target, int start, int end) {
206    for (int i = end - 1; i >= start; i--) {
207      if (array[i] == target) {
208        return i;
209      }
210    }
211    return -1;
212  }
213
214  /**
215   * Returns the least value present in {@code array}.
216   *
217   * @param array a <i>nonempty</i> array of {@code short} values
218   * @return the value present in {@code array} that is less than or equal to every other value in
219   *     the array
220   * @throws IllegalArgumentException if {@code array} is empty
221   */
222  @GwtIncompatible(
223      "Available in GWT! Annotation is to avoid conflict with GWT specialization of base class.")
224  public static short min(short... array) {
225    checkArgument(array.length > 0);
226    short min = array[0];
227    for (int i = 1; i < array.length; i++) {
228      if (array[i] < min) {
229        min = array[i];
230      }
231    }
232    return min;
233  }
234
235  /**
236   * Returns the greatest value present in {@code array}.
237   *
238   * @param array a <i>nonempty</i> array of {@code short} values
239   * @return the value present in {@code array} that is greater than or equal to every other value
240   *     in the array
241   * @throws IllegalArgumentException if {@code array} is empty
242   */
243  @GwtIncompatible(
244      "Available in GWT! Annotation is to avoid conflict with GWT specialization of base class.")
245  public static short max(short... array) {
246    checkArgument(array.length > 0);
247    short max = array[0];
248    for (int i = 1; i < array.length; i++) {
249      if (array[i] > max) {
250        max = array[i];
251      }
252    }
253    return max;
254  }
255
256  /**
257   * Returns the value nearest to {@code value} which is within the closed range {@code [min..max]}.
258   *
259   * <p>If {@code value} is within the range {@code [min..max]}, {@code value} is returned
260   * unchanged. If {@code value} is less than {@code min}, {@code min} is returned, and if {@code
261   * value} is greater than {@code max}, {@code max} is returned.
262   *
263   * @param value the {@code short} value to constrain
264   * @param min the lower bound (inclusive) of the range to constrain {@code value} to
265   * @param max the upper bound (inclusive) of the range to constrain {@code value} to
266   * @throws IllegalArgumentException if {@code min > max}
267   * @since 21.0
268   */
269  public static short constrainToRange(short value, short min, short max) {
270    checkArgument(min <= max, "min (%s) must be less than or equal to max (%s)", min, max);
271    return value < min ? min : value < max ? value : max;
272  }
273
274  /**
275   * Returns the values from each provided array combined into a single array. For example, {@code
276   * concat(new short[] {a, b}, new short[] {}, new short[] {c}} returns the array {@code {a, b,
277   * c}}.
278   *
279   * @param arrays zero or more {@code short} arrays
280   * @return a single array containing all the values from the source arrays, in order
281   * @throws IllegalArgumentException if the total number of elements in {@code arrays} does not fit
282   *     in an {@code int}
283   */
284  public static short[] concat(short[]... arrays) {
285    long length = 0;
286    for (short[] array : arrays) {
287      length += array.length;
288    }
289    short[] result = new short[checkNoOverflow(length)];
290    int pos = 0;
291    for (short[] array : arrays) {
292      System.arraycopy(array, 0, result, pos, array.length);
293      pos += array.length;
294    }
295    return result;
296  }
297
298  private static int checkNoOverflow(long result) {
299    checkArgument(
300        result == (int) result,
301        "the total number of elements (%s) in the arrays must fit in an int",
302        result);
303    return (int) result;
304  }
305
306  /**
307   * Returns a big-endian representation of {@code value} in a 2-element byte array; equivalent to
308   * {@code ByteBuffer.allocate(2).putShort(value).array()}. For example, the input value {@code
309   * (short) 0x1234} would yield the byte array {@code {0x12, 0x34}}.
310   *
311   * <p>If you need to convert and concatenate several values (possibly even of different types),
312   * use a shared {@link java.nio.ByteBuffer} instance, or use {@link
313   * com.google.common.io.ByteStreams#newDataOutput()} to get a growable buffer.
314   */
315  @GwtIncompatible // doesn't work
316  public static byte[] toByteArray(short value) {
317    return new byte[] {(byte) (value >> 8), (byte) value};
318  }
319
320  /**
321   * Returns the {@code short} value whose big-endian representation is stored in the first 2 bytes
322   * of {@code bytes}; equivalent to {@code ByteBuffer.wrap(bytes).getShort()}. For example, the
323   * input byte array {@code {0x54, 0x32}} would yield the {@code short} value {@code 0x5432}.
324   *
325   * <p>Arguably, it's preferable to use {@link java.nio.ByteBuffer}; that library exposes much more
326   * flexibility at little cost in readability.
327   *
328   * @throws IllegalArgumentException if {@code bytes} has fewer than 2 elements
329   */
330  @GwtIncompatible // doesn't work
331  public static short fromByteArray(byte[] bytes) {
332    checkArgument(bytes.length >= BYTES, "array too small: %s < %s", bytes.length, BYTES);
333    return fromBytes(bytes[0], bytes[1]);
334  }
335
336  /**
337   * Returns the {@code short} value whose byte representation is the given 2 bytes, in big-endian
338   * order; equivalent to {@code Shorts.fromByteArray(new byte[] {b1, b2})}.
339   *
340   * @since 7.0
341   */
342  @GwtIncompatible // doesn't work
343  public static short fromBytes(byte b1, byte b2) {
344    return (short) ((b1 << 8) | (b2 & 0xFF));
345  }
346
347  private static final class ShortConverter extends Converter<String, Short>
348      implements Serializable {
349    static final Converter<String, Short> INSTANCE = new ShortConverter();
350
351    @Override
352    protected Short doForward(String value) {
353      return Short.decode(value);
354    }
355
356    @Override
357    protected String doBackward(Short value) {
358      return value.toString();
359    }
360
361    @Override
362    public String toString() {
363      return "Shorts.stringConverter()";
364    }
365
366    private Object readResolve() {
367      return INSTANCE;
368    }
369
370    private static final long serialVersionUID = 1;
371  }
372
373  /**
374   * Returns a serializable converter object that converts between strings and shorts using {@link
375   * Short#decode} and {@link Short#toString()}. The returned converter throws {@link
376   * NumberFormatException} if the input string is invalid.
377   *
378   * <p><b>Warning:</b> please see {@link Short#decode} to understand exactly how strings are
379   * parsed. For example, the string {@code "0123"} is treated as <i>octal</i> and converted to the
380   * value {@code 83}.
381   *
382   * @since 16.0
383   */
384  public static Converter<String, Short> stringConverter() {
385    return ShortConverter.INSTANCE;
386  }
387
388  /**
389   * Returns an array containing the same values as {@code array}, but guaranteed to be of a
390   * specified minimum length. If {@code array} already has a length of at least {@code minLength},
391   * it is returned directly. Otherwise, a new array of size {@code minLength + padding} is
392   * returned, containing the values of {@code array}, and zeroes in the remaining places.
393   *
394   * @param array the source array
395   * @param minLength the minimum length the returned array must guarantee
396   * @param padding an extra amount to "grow" the array by if growth is necessary
397   * @throws IllegalArgumentException if {@code minLength} or {@code padding} is negative
398   * @return an array containing the values of {@code array}, with guaranteed minimum length {@code
399   *     minLength}
400   */
401  public static short[] ensureCapacity(short[] array, int minLength, int padding) {
402    checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
403    checkArgument(padding >= 0, "Invalid padding: %s", padding);
404    return (array.length < minLength) ? Arrays.copyOf(array, minLength + padding) : array;
405  }
406
407  /**
408   * Returns a string containing the supplied {@code short} values separated by {@code separator}.
409   * For example, {@code join("-", (short) 1, (short) 2, (short) 3)} returns the string {@code
410   * "1-2-3"}.
411   *
412   * @param separator the text that should appear between consecutive values in the resulting string
413   *     (but not at the start or end)
414   * @param array an array of {@code short} values, possibly empty
415   */
416  public static String join(String separator, short... array) {
417    checkNotNull(separator);
418    if (array.length == 0) {
419      return "";
420    }
421
422    // For pre-sizing a builder, just get the right order of magnitude
423    StringBuilder builder = new StringBuilder(array.length * 6);
424    builder.append(array[0]);
425    for (int i = 1; i < array.length; i++) {
426      builder.append(separator).append(array[i]);
427    }
428    return builder.toString();
429  }
430
431  /**
432   * Returns a comparator that compares two {@code short} arrays <a
433   * href="http://en.wikipedia.org/wiki/Lexicographical_order">lexicographically</a>. That is, it
434   * compares, using {@link #compare(short, short)}), the first pair of values that follow any
435   * common prefix, or when one array is a prefix of the other, treats the shorter array as the
436   * lesser. For example, {@code [] < [(short) 1] < [(short) 1, (short) 2] < [(short) 2]}.
437   *
438   * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
439   * support only identity equality), but it is consistent with {@link Arrays#equals(short[],
440   * short[])}.
441   *
442   * @since 2.0
443   */
444  public static Comparator<short[]> lexicographicalComparator() {
445    return LexicographicalComparator.INSTANCE;
446  }
447
448  private enum LexicographicalComparator implements Comparator<short[]> {
449    INSTANCE;
450
451    @Override
452    public int compare(short[] left, short[] right) {
453      int minLength = Math.min(left.length, right.length);
454      for (int i = 0; i < minLength; i++) {
455        int result = Short.compare(left[i], right[i]);
456        if (result != 0) {
457          return result;
458        }
459      }
460      return left.length - right.length;
461    }
462
463    @Override
464    public String toString() {
465      return "Shorts.lexicographicalComparator()";
466    }
467  }
468
469  /**
470   * Sorts the elements of {@code array} in descending order.
471   *
472   * @since 23.1
473   */
474  public static void sortDescending(short[] array) {
475    checkNotNull(array);
476    sortDescending(array, 0, array.length);
477  }
478
479  /**
480   * Sorts the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
481   * exclusive in descending order.
482   *
483   * @since 23.1
484   */
485  public static void sortDescending(short[] array, int fromIndex, int toIndex) {
486    checkNotNull(array);
487    checkPositionIndexes(fromIndex, toIndex, array.length);
488    Arrays.sort(array, fromIndex, toIndex);
489    reverse(array, fromIndex, toIndex);
490  }
491
492  /**
493   * Reverses the elements of {@code array}. This is equivalent to {@code
494   * Collections.reverse(Shorts.asList(array))}, but is likely to be more efficient.
495   *
496   * @since 23.1
497   */
498  public static void reverse(short[] array) {
499    checkNotNull(array);
500    reverse(array, 0, array.length);
501  }
502
503  /**
504   * Reverses the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
505   * exclusive. This is equivalent to {@code
506   * Collections.reverse(Shorts.asList(array).subList(fromIndex, toIndex))}, but is likely to be
507   * more efficient.
508   *
509   * @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
510   *     {@code toIndex > fromIndex}
511   * @since 23.1
512   */
513  public static void reverse(short[] array, int fromIndex, int toIndex) {
514    checkNotNull(array);
515    checkPositionIndexes(fromIndex, toIndex, array.length);
516    for (int i = fromIndex, j = toIndex - 1; i < j; i++, j--) {
517      short tmp = array[i];
518      array[i] = array[j];
519      array[j] = tmp;
520    }
521  }
522
523  /**
524   * Performs a right rotation of {@code array} of "distance" places, so that the first element is
525   * moved to index "distance", and the element at index {@code i} ends up at index {@code (distance
526   * + i) mod array.length}. This is equivalent to {@code Collections.rotate(Shorts.asList(array),
527   * distance)}, but is considerably faster and avoids allocation and garbage collection.
528   *
529   * <p>The provided "distance" may be negative, which will rotate left.
530   *
531   * @since 32.0.0
532   */
533  public static void rotate(short[] array, int distance) {
534    rotate(array, distance, 0, array.length);
535  }
536
537  /**
538   * Performs a right rotation of {@code array} between {@code fromIndex} inclusive and {@code
539   * toIndex} exclusive. This is equivalent to {@code
540   * Collections.rotate(Shorts.asList(array).subList(fromIndex, toIndex), distance)}, but is
541   * considerably faster and avoids allocations and garbage collection.
542   *
543   * <p>The provided "distance" may be negative, which will rotate left.
544   *
545   * @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
546   *     {@code toIndex > fromIndex}
547   * @since 32.0.0
548   */
549  public static void rotate(short[] array, int distance, int fromIndex, int toIndex) {
550    // See Ints.rotate for more details about possible algorithms here.
551    checkNotNull(array);
552    checkPositionIndexes(fromIndex, toIndex, array.length);
553    if (array.length <= 1) {
554      return;
555    }
556
557    int length = toIndex - fromIndex;
558    // Obtain m = (-distance mod length), a non-negative value less than "length". This is how many
559    // places left to rotate.
560    int m = -distance % length;
561    m = (m < 0) ? m + length : m;
562    // The current index of what will become the first element of the rotated section.
563    int newFirstIndex = m + fromIndex;
564    if (newFirstIndex == fromIndex) {
565      return;
566    }
567
568    reverse(array, fromIndex, newFirstIndex);
569    reverse(array, newFirstIndex, toIndex);
570    reverse(array, fromIndex, toIndex);
571  }
572
573  /**
574   * Returns an array containing each value of {@code collection}, converted to a {@code short}
575   * value in the manner of {@link Number#shortValue}.
576   *
577   * <p>Elements are copied from the argument collection as if by {@code collection.toArray()}.
578   * Calling this method is as thread-safe as calling that method.
579   *
580   * @param collection a collection of {@code Number} instances
581   * @return an array containing the same values as {@code collection}, in the same order, converted
582   *     to primitives
583   * @throws NullPointerException if {@code collection} or any of its elements is null
584   * @since 1.0 (parameter was {@code Collection<Short>} before 12.0)
585   */
586  public static short[] toArray(Collection<? extends Number> collection) {
587    if (collection instanceof ShortArrayAsList) {
588      return ((ShortArrayAsList) collection).toShortArray();
589    }
590
591    Object[] boxedArray = collection.toArray();
592    int len = boxedArray.length;
593    short[] array = new short[len];
594    for (int i = 0; i < len; i++) {
595      // checkNotNull for GWT (do not optimize)
596      array[i] = ((Number) checkNotNull(boxedArray[i])).shortValue();
597    }
598    return array;
599  }
600
601  /**
602   * Returns a fixed-size list backed by the specified array, similar to {@link
603   * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)}, but any attempt to
604   * set a value to {@code null} will result in a {@link NullPointerException}.
605   *
606   * <p>The returned list maintains the values, but not the identities, of {@code Short} objects
607   * written to or read from it. For example, whether {@code list.get(0) == list.get(0)} is true for
608   * the returned list is unspecified.
609   *
610   * <p>The returned list is serializable.
611   *
612   * @param backingArray the array to back the list
613   * @return a list view of the array
614   */
615  public static List<Short> asList(short... backingArray) {
616    if (backingArray.length == 0) {
617      return Collections.emptyList();
618    }
619    return new ShortArrayAsList(backingArray);
620  }
621
622  @GwtCompatible
623  private static class ShortArrayAsList extends AbstractList<Short>
624      implements RandomAccess, Serializable {
625    final short[] array;
626    final int start;
627    final int end;
628
629    ShortArrayAsList(short[] array) {
630      this(array, 0, array.length);
631    }
632
633    ShortArrayAsList(short[] array, int start, int end) {
634      this.array = array;
635      this.start = start;
636      this.end = end;
637    }
638
639    @Override
640    public int size() {
641      return end - start;
642    }
643
644    @Override
645    public boolean isEmpty() {
646      return false;
647    }
648
649    @Override
650    public Short get(int index) {
651      checkElementIndex(index, size());
652      return array[start + index];
653    }
654
655    @Override
656    public boolean contains(@Nullable Object target) {
657      // Overridden to prevent a ton of boxing
658      return (target instanceof Short) && Shorts.indexOf(array, (Short) target, start, end) != -1;
659    }
660
661    @Override
662    public int indexOf(@Nullable Object target) {
663      // Overridden to prevent a ton of boxing
664      if (target instanceof Short) {
665        int i = Shorts.indexOf(array, (Short) target, start, end);
666        if (i >= 0) {
667          return i - start;
668        }
669      }
670      return -1;
671    }
672
673    @Override
674    public int lastIndexOf(@Nullable Object target) {
675      // Overridden to prevent a ton of boxing
676      if (target instanceof Short) {
677        int i = Shorts.lastIndexOf(array, (Short) target, start, end);
678        if (i >= 0) {
679          return i - start;
680        }
681      }
682      return -1;
683    }
684
685    @Override
686    public Short set(int index, Short element) {
687      checkElementIndex(index, size());
688      short oldValue = array[start + index];
689      // checkNotNull for GWT (do not optimize)
690      array[start + index] = checkNotNull(element);
691      return oldValue;
692    }
693
694    @Override
695    public List<Short> subList(int fromIndex, int toIndex) {
696      int size = size();
697      checkPositionIndexes(fromIndex, toIndex, size);
698      if (fromIndex == toIndex) {
699        return Collections.emptyList();
700      }
701      return new ShortArrayAsList(array, start + fromIndex, start + toIndex);
702    }
703
704    @Override
705    public boolean equals(@Nullable Object object) {
706      if (object == this) {
707        return true;
708      }
709      if (object instanceof ShortArrayAsList) {
710        ShortArrayAsList that = (ShortArrayAsList) object;
711        int size = size();
712        if (that.size() != size) {
713          return false;
714        }
715        for (int i = 0; i < size; i++) {
716          if (array[start + i] != that.array[that.start + i]) {
717            return false;
718          }
719        }
720        return true;
721      }
722      return super.equals(object);
723    }
724
725    @Override
726    public int hashCode() {
727      int result = 1;
728      for (int i = start; i < end; i++) {
729        result = 31 * result + Shorts.hashCode(array[i]);
730      }
731      return result;
732    }
733
734    @Override
735    public String toString() {
736      StringBuilder builder = new StringBuilder(size() * 6);
737      builder.append('[').append(array[start]);
738      for (int i = start + 1; i < end; i++) {
739        builder.append(", ").append(array[i]);
740      }
741      return builder.append(']').toString();
742    }
743
744    short[] toShortArray() {
745      return Arrays.copyOfRange(array, start, end);
746    }
747
748    private static final long serialVersionUID = 0;
749  }
750}