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