/*
 * Copyright (C) 2008 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.common.primitives;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkPositionIndexes;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Converter;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.RandomAccess;
import java.util.Spliterator;
import java.util.Spliterators;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * Static utility methods pertaining to {@code long} primitives, that are not already found in
 * either {@link Long} or {@link Arrays}.
 *
 *
See the Guava User Guide article on primitive utilities.
 *
 * @author Kevin Bourrillion
 * @since 1.0
 */
@GwtCompatible
public final class Longs {
  private Longs() {}

  /**
   * The number of bytes required to represent a primitive {@code long} value.
   *
   *
Java 8 users: use {@link Long#BYTES} instead.
   */
  public static final int BYTES = Long.SIZE / Byte.SIZE;

  /**
   * The largest power of two that can be represented as a {@code long}.
   *
   * @since 10.0
   */
  public static final long MAX_POWER_OF_TWO = 1L << (Long.SIZE - 2);

  /**
   * Returns a hash code for {@code value}; equal to the result of invoking {@code ((Long)
   * value).hashCode()}.
   *
   *
This method always return the value specified by {@link Long#hashCode()} in java, which
   * might be different from {@code ((Long) value).hashCode()} in GWT because {@link
   * Long#hashCode()} in GWT does not obey the JRE contract.
   *
   *
Java 8 users: use {@link Long#hashCode(long)} instead.
   *
   * @param value a primitive {@code long} value
   * @return a hash code for the value
   */
  public static int hashCode(long value) {
    return (int) (value ^ (value >>> 32));
  }

  /**
   * Compares the two specified {@code long} values. The sign of the value returned is the same as
   * that of {@code ((Long) a).compareTo(b)}.
   *
   *
Note for Java 7 and later: this method should be treated as deprecated; use the
   * equivalent {@link Long#compare} method instead.
   *
   * @param a the first {@code long} to compare
   * @param b the second {@code long} to compare
   * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
   *     greater than {@code b}; or zero if they are equal
   */
  public static int compare(long a, long b) {
    return (a  b) ? 1 : 0);
  }

  /**
   * Returns {@code true} if {@code target} is present as an element anywhere in {@code array}.
   *
   * @param array an array of {@code long} values, possibly empty
   * @param target a primitive {@code long} value
   * @return {@code true} if {@code array[i] == target} for some value of {@code i}
   */
  public static boolean contains(long[] array, long target) {
    for (long value : array) {
      if (value == target) {
        return true;
      }
    }
    return false;
  }

  /**
   * Returns the index of the first appearance of the value {@code target} in {@code array}.
   *
   * @param array an array of {@code long} values, possibly empty
   * @param target a primitive {@code long} value
   * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no
   *     such index exists.
   */
  public static int indexOf(long[] array, long target) {
    return indexOf(array, target, 0, array.length);
  }

  // TODO(kevinb): consider making this public
  private static int indexOf(long[] array, long target, int start, int end) {
    for (int i = start; i < end; i++) {
      if (array[i] == target) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Returns the start position of the first occurrence of the specified {@code target} within
   * {@code array}, or {@code -1} if there is no such occurrence.
   *
   *
More formally, returns the lowest index {@code i} such that {@code Arrays.copyOfRange(array,
   * i, i + target.length)} contains exactly the same elements as {@code target}.
   *
   * @param array the array to search for the sequence {@code target}
   * @param target the array to search for as a sub-sequence of {@code array}
   */
  public static int indexOf(long[] array, long[] target) {
    checkNotNull(array, "array");
    checkNotNull(target, "target");
    if (target.length == 0) {
      return 0;
    }

    outer:
    for (int i = 0; i < array.length - target.length + 1; i++) {
      for (int j = 0; j < target.length; j++) {
        if (array[i + j] != target[j]) {
          continue outer;
        }
      }
      return i;
    }
    return -1;
  }

  /**
   * Returns the index of the last appearance of the value {@code target} in {@code array}.
   *
   * @param array an array of {@code long} values, possibly empty
   * @param target a primitive {@code long} value
   * @return the greatest index {@code i} for which {@code array[i] == target}, or {@code -1} if no
   *     such index exists.
   */
  public static int lastIndexOf(long[] array, long target) {
    return lastIndexOf(array, target, 0, array.length);
  }

  // TODO(kevinb): consider making this public
  private static int lastIndexOf(long[] array, long target, int start, int end) {
    for (int i = end - 1; i >= start; i--) {
      if (array[i] == target) {
        return i;
      }
    }
    return -1;
  }

  /**
   * Returns the least value present in {@code array}.
   *
   * @param array a nonempty array of {@code long} values
   * @return the value present in {@code array} that is less than or equal to every other value in
   *     the array
   * @throws IllegalArgumentException if {@code array} is empty
   */
  public static long min(long... array) {
    checkArgument(array.length > 0);
    long min = array[0];
    for (int i = 1; i < array.length; i++) {
      if (array[i] < min) {
        min = array[i];
      }
    }
    return min;
  }

  /**
   * Returns the greatest value present in {@code array}.
   *
   * @param array a nonempty array of {@code long} values
   * @return the value present in {@code array} that is greater than or equal to every other value
   *     in the array
   * @throws IllegalArgumentException if {@code array} is empty
   */
  public static long max(long... array) {
    checkArgument(array.length > 0);
    long max = array[0];
    for (int i = 1; i < array.length; i++) {
      if (array[i] > max) {
        max = array[i];
      }
    }
    return max;
  }

  /**
   * Returns the value nearest to {@code value} which is within the closed range {@code [min..max]}.
   *
   *
If {@code value} is within the range {@code [min..max]}, {@code value} is returned
   * unchanged. If {@code value} is less than {@code min}, {@code min} is returned, and if {@code
   * value} is greater than {@code max}, {@code max} is returned.
   *
   * @param value the {@code long} value to constrain
   * @param min the lower bound (inclusive) of the range to constrain {@code value} to
   * @param max the upper bound (inclusive) of the range to constrain {@code value} to
   * @throws IllegalArgumentException if {@code min > max}
   * @since 21.0
   */
  @Beta
  public static long constrainToRange(long value, long min, long max) {
    checkArgument(min <= max, "min (%s) must be less than or equal to max (%s)", min, max);
    return Math.min(Math.max(value, min), max);
  }

  /**
   * Returns the values from each provided array combined into a single array. For example, {@code
   * concat(new long[] {a, b}, new long[] {}, new long[] {c}} returns the array {@code {a, b, c}}.
   *
   * @param arrays zero or more {@code long} arrays
   * @return a single array containing all the values from the source arrays, in order
   */
  public static long[] concat(long[]... arrays) {
    int length = 0;
    for (long[] array : arrays) {
      length += array.length;
    }
    long[] result = new long[length];
    int pos = 0;
    for (long[] array : arrays) {
      System.arraycopy(array, 0, result, pos, array.length);
      pos += array.length;
    }
    return result;
  }

  /**
   * Returns a big-endian representation of {@code value} in an 8-element byte array; equivalent to
   * {@code ByteBuffer.allocate(8).putLong(value).array()}. For example, the input value {@code
   * 0x1213141516171819L} would yield the byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   * 0x18, 0x19}}.
   *
   *
If you need to convert and concatenate several values (possibly even of different types),
   * use a shared {@link java.nio.ByteBuffer} instance, or use {@link
   * com.google.common.io.ByteStreams#newDataOutput()} to get a growable buffer.
   */
  public static byte[] toByteArray(long value) {
    // Note that this code needs to stay compatible with GWT, which has known
    // bugs when narrowing byte casts of long values occur.
    byte[] result = new byte[8];
    for (int i = 7; i >= 0; i--) {
      result[i] = (byte) (value & 0xffL);
      value >>= 8;
    }
    return result;
  }

  /**
   * Returns the {@code long} value whose big-endian representation is stored in the first 8 bytes
   * of {@code bytes}; equivalent to {@code ByteBuffer.wrap(bytes).getLong()}. For example, the
   * input byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}} would yield the
   * {@code long} value {@code 0x1213141516171819L}.
   *
   *
Arguably, it's preferable to use {@link java.nio.ByteBuffer}; that library exposes much more
   * flexibility at little cost in readability.
   *
   * @throws IllegalArgumentException if {@code bytes} has fewer than 8 elements
   */
  public static long fromByteArray(byte[] bytes) {
    checkArgument(bytes.length >= BYTES, "array too small: %s < %s", bytes.length, BYTES);
    return fromBytes(
        bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]);
  }

  /**
   * Returns the {@code long} value whose byte representation is the given 8 bytes, in big-endian
   * order; equivalent to {@code Longs.fromByteArray(new byte[] {b1, b2, b3, b4, b5, b6, b7, b8})}.
   *
   * @since 7.0
   */
  public static long fromBytes(
      byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7, byte b8) {
    return (b1 & 0xFFL) << 56
        | (b2 & 0xFFL) << 48
        | (b3 & 0xFFL) << 40
        | (b4 & 0xFFL) << 32
        | (b5 & 0xFFL) << 24
        | (b6 & 0xFFL) << 16
        | (b7 & 0xFFL) << 8
        | (b8 & 0xFFL);
  }

  /*
   * Moving asciiDigits into this static holder class lets ProGuard eliminate and inline the Longs
   * class.
   */
  static final class AsciiDigits {
    private AsciiDigits() {}

    private static final byte[] asciiDigits;

    static {
      byte[] result = new byte[128];
      Arrays.fill(result, (byte) -1);
      for (int i = 0; i <= 9; i++) {
        result['0' + i] = (byte) i;
      }
      for (int i = 0; i <= 26; i++) {
        result['A' + i] = (byte) (10 + i);
        result['a' + i] = (byte) (10 + i);
      }
      asciiDigits = result;
    }

    static int digit(char c) {
      return (c < 128) ? asciiDigits[c] : -1;
    }
  }

  /**
   * Parses the specified string as a signed decimal long value. The ASCII character {@code '-'} (
   * '\u002D') is recognized as the minus sign.
   *
   *
Unlike {@link Long#parseLong(String)}, this method returns {@code null} instead of throwing
   * an exception if parsing fails. Additionally, this method only accepts ASCII digits, and returns
   * {@code null} if non-ASCII digits are present in the string.
   *
   *
Note that strings prefixed with ASCII {@code '+'} are rejected, even under JDK 7, despite
   * the change to {@link Long#parseLong(String)} for that version.
   *
   * @param string the string representation of a long value
   * @return the long value represented by {@code string}, or {@code null} if {@code string} has a
   *     length of zero or cannot be parsed as a long value
   * @since 14.0
   */
  @Beta
  public static @Nullable Long tryParse(String string) {
    return tryParse(string, 10);
  }

  /**
   * Parses the specified string as a signed long value using the specified radix. The ASCII
   * character {@code '-'} ('\u002D') is recognized as the minus sign.
   *
   *
Unlike {@link Long#parseLong(String, int)}, this method returns {@code null} instead of
   * throwing an exception if parsing fails. Additionally, this method only accepts ASCII digits,
   * and returns {@code null} if non-ASCII digits are present in the string.
   *
   *
Note that strings prefixed with ASCII {@code '+'} are rejected, even under JDK 7, despite
   * the change to {@link Long#parseLong(String, int)} for that version.
   *
   * @param string the string representation of an long value
   * @param radix the radix to use when parsing
   * @return the long value represented by {@code string} using {@code radix}, or {@code null} if
   *     {@code string} has a length of zero or cannot be parsed as a long value
   * @throws IllegalArgumentException if {@code radix < Character.MIN_RADIX} or {@code radix >
   *     Character.MAX_RADIX}
   * @since 19.0
   */
  @Beta
  public static @Nullable Long tryParse(String string, int radix) {
    if (checkNotNull(string).isEmpty()) {
      return null;
    }
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
      throw new IllegalArgumentException(
          "radix must be between MIN_RADIX and MAX_RADIX but was " + radix);
    }
    boolean negative = string.charAt(0) == '-';
    int index = negative ? 1 : 0;
    if (index == string.length()) {
      return null;
    }
    int digit = AsciiDigits.digit(string.charAt(index++));
    if (digit < 0 || digit >= radix) {
      return null;
    }
    long accum = -digit;

    long cap = Long.MIN_VALUE / radix;

    while (index < string.length()) {
      digit = AsciiDigits.digit(string.charAt(index++));
      if (digit < 0 || digit >= radix || accum < cap) {
        return null;
      }
      accum *= radix;
      if (accum < Long.MIN_VALUE + digit) {
        return null;
      }
      accum -= digit;
    }

    if (negative) {
      return accum;
    } else if (accum == Long.MIN_VALUE) {
      return null;
    } else {
      return -accum;
    }
  }

  private static final class LongConverter extends Converter<String, Long> implements Serializable {
    static final LongConverter INSTANCE = new LongConverter();

    @Override
    protected Long doForward(String value) {
      return Long.decode(value);
    }

    @Override
    protected String doBackward(Long value) {
      return value.toString();
    }

    @Override
    public String toString() {
      return "Longs.stringConverter()";
    }

    private Object readResolve() {
      return INSTANCE;
    }

    private static final long serialVersionUID = 1;
  }

  /**
   * Returns a serializable converter object that converts between strings and longs using {@link
   * Long#decode} and {@link Long#toString()}. The returned converter throws {@link
   * NumberFormatException} if the input string is invalid.
   *
   *
Warning: please see {@link Long#decode} to understand exactly how strings are parsed.
   * For example, the string {@code "0123"} is treated as octal and converted to the value
   * {@code 83L}.
   *
   * @since 16.0
   */
  @Beta
  public static Converter<String, Long> stringConverter() {
    return LongConverter.INSTANCE;
  }

  /**
   * Returns an array containing the same values as {@code array}, but guaranteed to be of a
   * specified minimum length. If {@code array} already has a length of at least {@code minLength},
   * it is returned directly. Otherwise, a new array of size {@code minLength + padding} is
   * returned, containing the values of {@code array}, and zeroes in the remaining places.
   *
   * @param array the source array
   * @param minLength the minimum length the returned array must guarantee
   * @param padding an extra amount to "grow" the array by if growth is necessary
   * @throws IllegalArgumentException if {@code minLength} or {@code padding} is negative
   * @return an array containing the values of {@code array}, with guaranteed minimum length {@code
   *     minLength}
   */
  public static long[] ensureCapacity(long[] array, int minLength, int padding) {
    checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
    checkArgument(padding >= 0, "Invalid padding: %s", padding);
    return (array.length < minLength) ? Arrays.copyOf(array, minLength + padding) : array;
  }

  /**
   * Returns a string containing the supplied {@code long} values separated by {@code separator}.
   * For example, {@code join("-", 1L, 2L, 3L)} returns the string {@code "1-2-3"}.
   *
   * @param separator the text that should appear between consecutive values in the resulting string
   *     (but not at the start or end)
   * @param array an array of {@code long} values, possibly empty
   */
  public static String join(String separator, long... array) {
    checkNotNull(separator);
    if (array.length == 0) {
      return "";
    }

    // For pre-sizing a builder, just get the right order of magnitude
    StringBuilder builder = new StringBuilder(array.length * 10);
    builder.append(array[0]);
    for (int i = 1; i < array.length; i++) {
      builder.append(separator).append(array[i]);
    }
    return builder.toString();
  }

  /**
   * Returns a comparator that compares two {@code long} arrays lexicographically. That is, it
   * compares, using {@link #compare(long, long)}), the first pair of values that follow any common
   * prefix, or when one array is a prefix of the other, treats the shorter array as the lesser. For
   * example, {@code [] < [1L] < [1L, 2L] < [2L]}.
   *
   *
The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
   * support only identity equality), but it is consistent with {@link Arrays#equals(long[],
   * long[])}.
   *
   * @since 2.0
   */
  public static Comparator<long[]> lexicographicalComparator() {
    return LexicographicalComparator.INSTANCE;
  }

  private enum LexicographicalComparator implements Comparator<long[]> {
    INSTANCE;

    @Override
    public int compare(long[] left, long[] right) {
      int minLength = Math.min(left.length, right.length);
      for (int i = 0; i < minLength; i++) {
        int result = Longs.compare(left[i], right[i]);
        if (result != 0) {
          return result;
        }
      }
      return left.length - right.length;
    }

    @Override
    public String toString() {
      return "Longs.lexicographicalComparator()";
    }
  }

  /**
   * Sorts the elements of {@code array} in descending order.
   *
   * @since 23.1
   */
  public static void sortDescending(long[] array) {
    checkNotNull(array);
    sortDescending(array, 0, array.length);
  }

  /**
   * Sorts the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
   * exclusive in descending order.
   *
   * @since 23.1
   */
  public static void sortDescending(long[] array, int fromIndex, int toIndex) {
    checkNotNull(array);
    checkPositionIndexes(fromIndex, toIndex, array.length);
    Arrays.sort(array, fromIndex, toIndex);
    reverse(array, fromIndex, toIndex);
  }

  /**
   * Reverses the elements of {@code array}. This is equivalent to {@code
   * Collections.reverse(Longs.asList(array))}, but is likely to be more efficient.
   *
   * @since 23.1
   */
  public static void reverse(long[] array) {
    checkNotNull(array);
    reverse(array, 0, array.length);
  }

  /**
   * Reverses the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
   * exclusive. This is equivalent to {@code
   * Collections.reverse(Longs.asList(array).subList(fromIndex, toIndex))}, but is likely to be more
   * efficient.
   *
   * @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
   *     {@code toIndex > fromIndex}
   * @since 23.1
   */
  public static void reverse(long[] array, int fromIndex, int toIndex) {
    checkNotNull(array);
    checkPositionIndexes(fromIndex, toIndex, array.length);
    for (int i = fromIndex, j = toIndex - 1; i < j; i++, j--) {
      long tmp = array[i];
      array[i] = array[j];
      array[j] = tmp;
    }
  }

  /**
   * Returns an array containing each value of {@code collection}, converted to a {@code long} value
   * in the manner of {@link Number#longValue}.
   *
   *
Elements are copied from the argument collection as if by {@code collection.toArray()}.
   * Calling this method is as thread-safe as calling that method.
   *
   * @param collection a collection of {@code Number} instances
   * @return an array containing the same values as {@code collection}, in the same order, converted
   *     to primitives
   * @throws NullPointerException if {@code collection} or any of its elements is null
   * @since 1.0 (parameter was {@code Collection<Long>} before 12.0)
   */
  public static long[] toArray(Collection<? extends Number> collection) {
    if (collection instanceof LongArrayAsList) {
      return ((LongArrayAsList) collection).toLongArray();
    }

    Object[] boxedArray = collection.toArray();
    int len = boxedArray.length;
    long[] array = new long[len];
    for (int i = 0; i < len; i++) {
      // checkNotNull for GWT (do not optimize)
      array[i] = ((Number) checkNotNull(boxedArray[i])).longValue();
    }
    return array;
  }

  /**
   * Returns a fixed-size list backed by the specified array, similar to {@link
   * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)}, but any attempt to
   * set a value to {@code null} will result in a {@link NullPointerException}.
   *
   *
The returned list maintains the values, but not the identities, of {@code Long} objects
   * written to or read from it. For example, whether {@code list.get(0) == list.get(0)} is true for
   * the returned list is unspecified.
   *
   *
Note: when possible, you should represent your data as an {@link ImmutableLongArray}
   * instead, which has an {@link ImmutableLongArray#asList asList} view.
   *
   * @param backingArray the array to back the list
   * @return a list view of the array
   */
  public static List<Long> asList(long... backingArray) {
    if (backingArray.length == 0) {
      return Collections.emptyList();
    }
    return new LongArrayAsList(backingArray);
  }

  @GwtCompatible
  private static class LongArrayAsList extends AbstractList<Long>
      implements RandomAccess, Serializable {
    final long[] array;
    final int start;
    final int end;

    LongArrayAsList(long[] array) {
      this(array, 0, array.length);
    }

    LongArrayAsList(long[] array, int start, int end) {
      this.array = array;
      this.start = start;
      this.end = end;
    }

    @Override
    public int size() {
      return end - start;
    }

    @Override
    public boolean isEmpty() {
      return false;
    }

    @Override
    public Long get(int index) {
      checkElementIndex(index, size());
      return array[start + index];
    }

    @Override
    public Spliterator.OfLong spliterator() {
      return Spliterators.spliterator(array, start, end, 0);
    }

    @Override
    public boolean contains(Object target) {
      // Overridden to prevent a ton of boxing
      return (target instanceof Long) && Longs.indexOf(array, (Long) target, start, end) != -1;
    }

    @Override
    public int indexOf(Object target) {
      // Overridden to prevent a ton of boxing
      if (target instanceof Long) {
        int i = Longs.indexOf(array, (Long) target, start, end);
        if (i >= 0) {
          return i - start;
        }
      }
      return -1;
    }

    @Override
    public int lastIndexOf(Object target) {
      // Overridden to prevent a ton of boxing
      if (target instanceof Long) {
        int i = Longs.lastIndexOf(array, (Long) target, start, end);
        if (i >= 0) {
          return i - start;
        }
      }
      return -1;
    }

    @Override
    public Long set(int index, Long element) {
      checkElementIndex(index, size());
      long oldValue = array[start + index];
      // checkNotNull for GWT (do not optimize)
      array[start + index] = checkNotNull(element);
      return oldValue;
    }

    @Override
    public List<Long> subList(int fromIndex, int toIndex) {
      int size = size();
      checkPositionIndexes(fromIndex, toIndex, size);
      if (fromIndex == toIndex) {
        return Collections.emptyList();
      }
      return new LongArrayAsList(array, start + fromIndex, start + toIndex);
    }

    @Override
    public boolean equals(@Nullable Object object) {
      if (object == this) {
        return true;
      }
      if (object instanceof LongArrayAsList) {
        LongArrayAsList that = (LongArrayAsList) object;
        int size = size();
        if (that.size() != size) {
          return false;
        }
        for (int i = 0; i < size; i++) {
          if (array[start + i] != that.array[that.start + i]) {
            return false;
          }
        }
        return true;
      }
      return super.equals(object);
    }

    @Override
    public int hashCode() {
      int result = 1;
      for (int i = start; i < end; i++) {
        result = 31 * result + Longs.hashCode(array[i]);
      }
      return result;
    }

    @Override
    public String toString() {
      StringBuilder builder = new StringBuilder(size() * 10);
      builder.append('[').append(array[start]);
      for (int i = start + 1; i < end; i++) {
        builder.append(", ").append(array[i]);
      }
      return builder.append(']').toString();
    }

    long[] toLongArray() {
      return Arrays.copyOfRange(array, start, end);
    }

    private static final long serialVersionUID = 0;
  }
}


/*
 * Copyright (C) 2011 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.BoundType.CLOSED;
import static com.google.common.collect.BoundType.OPEN;

import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Objects;
import java.io.Serializable;
import java.util.Comparator;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A generalized interval on any ordering, for internal use. Supports {@code null}. Unlike {@link
 * Range}, this allows the use of an arbitrary comparator. This is designed for use in the
 * implementation of subcollections of sorted collection types.
 *
 * <p>Whenever possible, use {@code Range} instead, which is better supported.
 *
 * @author Louis Wasserman
 */
@GwtCompatible(serializable = true)
final class GeneralRange<T> implements Serializable {
  /** Converts a Range to a GeneralRange. */
  static <T extends Comparable> GeneralRange<T> from(Range<T> range) {
    @Nullable T lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : null;
    BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : OPEN;

    @Nullable T upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : null;
    BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : OPEN;
    return new GeneralRange<T>(
        Ordering.natural(),
        range.hasLowerBound(),
        lowerEndpoint,
        lowerBoundType,
        range.hasUpperBound(),
        upperEndpoint,
        upperBoundType);
  }

  /** Returns the whole range relative to the specified comparator. */
  static <T> GeneralRange<T> all(Comparator<? super T> comparator) {
    return new GeneralRange<T>(comparator, false, null, OPEN, false, null, OPEN);
  }

  /**
   * Returns everything above the endpoint relative to the specified comparator, with the specified
   * endpoint behavior.
   */
  static <T> GeneralRange<T> downTo(
      Comparator<? super T> comparator, @Nullable T endpoint, BoundType boundType) {
    return new GeneralRange<T>(comparator, true, endpoint, boundType, false, null, OPEN);
  }

  /**
   * Returns everything below the endpoint relative to the specified comparator, with the specified
   * endpoint behavior.
   */
  static <T> GeneralRange<T> upTo(
      Comparator<? super T> comparator, @Nullable T endpoint, BoundType boundType) {
    return new GeneralRange<T>(comparator, false, null, OPEN, true, endpoint, boundType);
  }

  /**
   * Returns everything between the endpoints relative to the specified comparator, with the
   * specified endpoint behavior.
   */
  static <T> GeneralRange<T> range(
      Comparator<? super T> comparator,
      @Nullable T lower,
      BoundType lowerType,
      @Nullable T upper,
      BoundType upperType) {
    return new GeneralRange<T>(comparator, true, lower, lowerType, true, upper, upperType);
  }

  private final Comparator<? super T> comparator;
  private final boolean hasLowerBound;
  private final @Nullable T lowerEndpoint;
  private final BoundType lowerBoundType;
  private final boolean hasUpperBound;
  private final @Nullable T upperEndpoint;
  private final BoundType upperBoundType;

  private GeneralRange(
      Comparator<? super T> comparator,
      boolean hasLowerBound,
      @Nullable T lowerEndpoint,
      BoundType lowerBoundType,
      boolean hasUpperBound,
      @Nullable T upperEndpoint,
      BoundType upperBoundType) {
    this.comparator = checkNotNull(comparator);
    this.hasLowerBound = hasLowerBound;
    this.hasUpperBound = hasUpperBound;
    this.lowerEndpoint = lowerEndpoint;
    this.lowerBoundType = checkNotNull(lowerBoundType);
    this.upperEndpoint = upperEndpoint;
    this.upperBoundType = checkNotNull(upperBoundType);

    if (hasLowerBound) {
      comparator.compare(lowerEndpoint, lowerEndpoint);
    }
    if (hasUpperBound) {
      comparator.compare(upperEndpoint, upperEndpoint);
    }
    if (hasLowerBound && hasUpperBound) {
      int cmp = comparator.compare(lowerEndpoint, upperEndpoint);
      // be consistent with Range
      checkArgument(
          cmp <= 0, "lowerEndpoint (%s) > upperEndpoint (%s)", lowerEndpoint, upperEndpoint);
      if (cmp == 0) {
        checkArgument(lowerBoundType != OPEN | upperBoundType != OPEN);
      }
    }
  }

  Comparator<? super T> comparator() {
    return comparator;
  }

  boolean hasLowerBound() {
    return hasLowerBound;
  }

  boolean hasUpperBound() {
    return hasUpperBound;
  }

  boolean isEmpty() {
    return (hasUpperBound() && tooLow(getUpperEndpoint()))
        || (hasLowerBound() && tooHigh(getLowerEndpoint()));
  }

  boolean tooLow(@Nullable T t) {
    if (!hasLowerBound()) {
      return false;
    }
    T lbound = getLowerEndpoint();
    int cmp = comparator.compare(t, lbound);
    return cmp < 0 | (cmp == 0 & getLowerBoundType() == OPEN);
  }

  boolean tooHigh(@Nullable T t) {
    if (!hasUpperBound()) {
      return false;
    }
    T ubound = getUpperEndpoint();
    int cmp = comparator.compare(t, ubound);
    return cmp > 0 | (cmp == 0 & getUpperBoundType() == OPEN);
  }

  boolean contains(@Nullable T t) {
    return !tooLow(t) && !tooHigh(t);
  }

  /**
   * Returns the intersection of the two ranges, or an empty range if their intersection is empty.
   */
  GeneralRange<T> intersect(GeneralRange<T> other) {
    checkNotNull(other);
    checkArgument(comparator.equals(other.comparator));

    boolean hasLowBound = this.hasLowerBound;
    @Nullable T lowEnd = getLowerEndpoint();
    BoundType lowType = getLowerBoundType();
    if (!hasLowerBound()) {
      hasLowBound = other.hasLowerBound;
      lowEnd = other.getLowerEndpoint();
      lowType = other.getLowerBoundType();
    } else if (other.hasLowerBound()) {
      int cmp = comparator.compare(getLowerEndpoint(), other.getLowerEndpoint());
      if (cmp < 0 || (cmp == 0 && other.getLowerBoundType() == OPEN)) {
        lowEnd = other.getLowerEndpoint();
        lowType = other.getLowerBoundType();
      }
    }

    boolean hasUpBound = this.hasUpperBound;
    @Nullable T upEnd = getUpperEndpoint();
    BoundType upType = getUpperBoundType();
    if (!hasUpperBound()) {
      hasUpBound = other.hasUpperBound;
      upEnd = other.getUpperEndpoint();
      upType = other.getUpperBoundType();
    } else if (other.hasUpperBound()) {
      int cmp = comparator.compare(getUpperEndpoint(), other.getUpperEndpoint());
      if (cmp > 0 || (cmp == 0 && other.getUpperBoundType() == OPEN)) {
        upEnd = other.getUpperEndpoint();
        upType = other.getUpperBoundType();
      }
    }

    if (hasLowBound && hasUpBound) {
      int cmp = comparator.compare(lowEnd, upEnd);
      if (cmp > 0 || (cmp == 0 && lowType == OPEN && upType == OPEN)) {
        // force allowed empty range
        lowEnd = upEnd;
        lowType = OPEN;
        upType = CLOSED;
      }
    }

    return new GeneralRange<T>(comparator, hasLowBound, lowEnd, lowType, hasUpBound, upEnd, upType);
  }

  @Override
  public boolean equals(@Nullable Object obj) {
    if (obj instanceof GeneralRange) {
      GeneralRange<?> r = (GeneralRange<?>) obj;
      return comparator.equals(r.comparator)
          && hasLowerBound == r.hasLowerBound
          && hasUpperBound == r.hasUpperBound
          && getLowerBoundType().equals(r.getLowerBoundType())
          && getUpperBoundType().equals(r.getUpperBoundType())
          && Objects.equal(getLowerEndpoint(), r.getLowerEndpoint())
          && Objects.equal(getUpperEndpoint(), r.getUpperEndpoint());
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(
        comparator,
        getLowerEndpoint(),
        getLowerBoundType(),
        getUpperEndpoint(),
        getUpperBoundType());
  }

  private transient @MonotonicNonNull GeneralRange<T> reverse;

  /** Returns the same range relative to the reversed comparator. */
  GeneralRange<T> reverse() {
    GeneralRange<T> result = reverse;
    if (result == null) {
      result =
          new GeneralRange<T>(
              Ordering.from(comparator).reverse(),
              hasUpperBound,
              getUpperEndpoint(),
              getUpperBoundType(),
              hasLowerBound,
              getLowerEndpoint(),
              getLowerBoundType());
      result.reverse = this;
      return this.reverse = result;
    }
    return result;
  }

  @Override
  public String toString() {
    return comparator
        + ":"
        + (lowerBoundType == CLOSED ? '[' : '(')
        + (hasLowerBound ? lowerEndpoint : "-\u221e")
        + ','
        + (hasUpperBound ? upperEndpoint : "\u221e")
        + (upperBoundType == CLOSED ? ']' : ')');
  }

  T getLowerEndpoint() {
    return lowerEndpoint;
  }

  BoundType getLowerBoundType() {
    return lowerBoundType;
  }

  T getUpperEndpoint() {
    return upperEndpoint;
  }

  BoundType getUpperBoundType() {
    return upperBoundType;
  }
}


/*
 * Copyright (C) 2009 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.Beta;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collector;

/**
 * GWT emulated version of {@link com.google.common.collect.ImmutableSet}. For the unsorted sets,
 * they are thin wrapper around {@link java.util.Collections#emptySet()}, {@link
 * Collections#singleton(Object)} and {@link java.util.LinkedHashSet} for empty, singleton and
 * regular sets respectively. For the sorted sets, it's a thin wrapper around {@link
 * java.util.TreeSet}.
 *
 * @see ImmutableSortedSet
 * @author Hayward Chan
 */
@SuppressWarnings("serial") // Serialization only done in GWT.
public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> {
  ImmutableSet() {}

  @Beta
  public static <E> Collector<E, ?, ImmutableSet<E>> toImmutableSet() {
    return CollectCollectors.toImmutableSet();
  }

  // Casting to any type is safe because the set will never hold any elements.
  @SuppressWarnings({"unchecked"})
  public static <E> ImmutableSet<E> of() {
    return (ImmutableSet<E>) RegularImmutableSet.EMPTY;
  }

  public static <E> ImmutableSet<E> of(E element) {
    return new SingletonImmutableSet<E>(element);
  }

  @SuppressWarnings("unchecked")
  public static <E> ImmutableSet<E> of(E e1, E e2) {
    return create(e1, e2);
  }

  @SuppressWarnings("unchecked")
  public static <E> ImmutableSet<E> of(E e1, E e2, E e3) {
    return create(e1, e2, e3);
  }

  @SuppressWarnings("unchecked")
  public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) {
    return create(e1, e2, e3, e4);
  }

  @SuppressWarnings("unchecked")
  public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) {
    return create(e1, e2, e3, e4, e5);
  }

  @SuppressWarnings("unchecked")
  public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
    int size = others.length + 6;
    List<E> all = new ArrayList<E>(size);
    Collections.addAll(all, e1, e2, e3, e4, e5, e6);
    Collections.addAll(all, others);
    return copyOf(all.iterator());
  }

  public static <E> ImmutableSet<E> copyOf(E[] elements) {
    checkNotNull(elements);
    switch (elements.length) {
      case 0:
        return of();
      case 1:
        return of(elements[0]);
      default:
        return create(elements);
    }
  }

  public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) {
    Iterable<? extends E> iterable = elements;
    return copyOf(iterable);
  }

  public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
    if (elements instanceof ImmutableSet && !(elements instanceof ImmutableSortedSet)) {
      @SuppressWarnings("unchecked") // all supported methods are covariant
      ImmutableSet<E> set = (ImmutableSet<E>) elements;
      return set;
    }
    return copyOf(elements.iterator());
  }

  public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) {
    if (!elements.hasNext()) {
      return of();
    }
    E first = elements.next();
    if (!elements.hasNext()) {
      // TODO: Remove "ImmutableSet.<E>" when eclipse bug is fixed.
      return ImmutableSet.<E>of(first);
    }

    Set<E> delegate = Sets.newLinkedHashSet();
    delegate.add(checkNotNull(first));
    do {
      delegate.add(checkNotNull(elements.next()));
    } while (elements.hasNext());

    return unsafeDelegate(delegate);
  }

  // Factory methods that skips the null checks on elements, only used when
  // the elements are known to be non-null.
  static <E> ImmutableSet<E> unsafeDelegate(Set<E> delegate) {
    switch (delegate.size()) {
      case 0:
        return of();
      case 1:
        return new SingletonImmutableSet<E>(delegate.iterator().next());
      default:
        return new RegularImmutableSet<E>(delegate);
    }
  }

  private static <E> ImmutableSet<E> create(E... elements) {
    // Create the set first, to remove duplicates if necessary.
    Set<E> set = Sets.newLinkedHashSet();
    Collections.addAll(set, elements);
    for (E element : set) {
      checkNotNull(element);
    }

    switch (set.size()) {
      case 0:
        return of();
      case 1:
        return new SingletonImmutableSet<E>(set.iterator().next());
      default:
        return new RegularImmutableSet<E>(set);
    }
  }

  @Override
  public boolean equals(Object obj) {
    return Sets.equalsImpl(this, obj);
  }

  @Override
  public int hashCode() {
    return Sets.hashCodeImpl(this);
  }

  // This declaration is needed to make Set.iterator() and
  // ImmutableCollection.iterator() appear consistent to javac's type inference.
  @Override
  public abstract UnmodifiableIterator<E> iterator();

  abstract static class Indexed<E> extends ImmutableSet<E> {
    abstract E get(int index);

    @Override
    public UnmodifiableIterator<E> iterator() {
      return asList().iterator();
    }

    @Override
    ImmutableList<E> createAsList() {
      return new ImmutableAsList<E>() {
        @Override
        public E get(int index) {
          return Indexed.this.get(index);
        }

        @Override
        Indexed<E> delegateCollection() {
          return Indexed.this;
        }
      };
    }
  }

  public static <E> Builder<E> builder() {
    return new Builder<E>();
  }

  public static <E> Builder<E> builderWithExpectedSize(int size) {
    return new Builder<E>(size);
  }

  public static class Builder<E> extends ImmutableCollection.Builder<E> {
    // accessed directly by ImmutableSortedSet
    final ArrayList<E> contents;

    public Builder() {
      this.contents = Lists.newArrayList();
    }

    Builder(int initialCapacity) {
      this.contents = Lists.newArrayListWithCapacity(initialCapacity);
    }

    @Override
    public Builder<E> add(E element) {
      contents.add(checkNotNull(element));
      return this;
    }

    @Override
    public Builder<E> add(E... elements) {
      checkNotNull(elements); // for GWT
      contents.ensureCapacity(contents.size() + elements.length);
      super.add(elements);
      return this;
    }

    @Override
    public Builder<E> addAll(Iterable<? extends E> elements) {
      if (elements instanceof Collection) {
        Collection<?> collection = (Collection<?>) elements;
        contents.ensureCapacity(contents.size() + collection.size());
      }
      super.addAll(elements);
      return this;
    }

    @Override
    public Builder<E> addAll(Iterator<? extends E> elements) {
      super.addAll(elements);
      return this;
    }

    Builder<E> combine(Builder<E> builder) {
      contents.addAll(builder.contents);
      return this;
    }

    @Override
    public ImmutableSet<E> build() {
      return copyOf(contents.iterator());
    }
  }
}


/*
 * Copyright (C) 2008 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.CollectPreconditions.checkEntryNotNull;
import static com.google.common.collect.CollectPreconditions.checkNonnegative;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.concurrent.LazyInit;
import com.google.j2objc.annotations.RetainedWith;
import com.google.j2objc.annotations.WeakOuter;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import org.checkerframework.checker.nullness.compatqual.MonotonicNonNullDecl;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * A {@link Map} whose contents will never change, with many other important properties detailed at
 * {@link ImmutableCollection}.
 *
 *
See the Guava User Guide article on  immutable collections.
 *
 * @author Jesse Wilson
 * @author Kevin Bourrillion
 * @since 2.0
 */
@GwtCompatible(serializable = true, emulated = true)
@SuppressWarnings("serial") // we're overriding default serialization
public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {

  /**
   * Returns the empty map. This map behaves and performs comparably to {@link
   * Collections#emptyMap}, and is preferable mainly for consistency and maintainability of your
   * code.
   */
  @SuppressWarnings("unchecked")
  public static <K, V> ImmutableMap<K, V> of() {
    return (ImmutableMap<K, V>) RegularImmutableMap.EMPTY;
  }

  /**
   * Returns an immutable map containing a single entry. This map behaves and performs comparably to
   * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable
   * mainly for consistency and maintainability of your code.
   */
  public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
    checkEntryNotNull(k1, v1);
    return RegularImmutableMap.create(1, new Object[] {k1, v1});
  }

  /**
   * Returns an immutable map containing the given entries, in order.
   *
   * @throws IllegalArgumentException if duplicate keys are provided
   */
  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
    checkEntryNotNull(k1, v1);
    checkEntryNotNull(k2, v2);
    return RegularImmutableMap.create(2, new Object[] {k1, v1, k2, v2});
  }

  /**
   * Returns an immutable map containing the given entries, in order.
   *
   * @throws IllegalArgumentException if duplicate keys are provided
   */
  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
    checkEntryNotNull(k1, v1);
    checkEntryNotNull(k2, v2);
    checkEntryNotNull(k3, v3);
    return RegularImmutableMap.create(3, new Object[] {k1, v1, k2, v2, k3, v3});
  }

  /**
   * Returns an immutable map containing the given entries, in order.
   *
   * @throws IllegalArgumentException if duplicate keys are provided
   */
  public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
    checkEntryNotNull(k1, v1);
    checkEntryNotNull(k2, v2);
    checkEntryNotNull(k3, v3);
    checkEntryNotNull(k4, v4);
    return RegularImmutableMap.create(4, new Object[] {k1, v1, k2, v2, k3, v3, k4, v4});
  }

  /**
   * Returns an immutable map containing the given entries, in order.
   *
   * @throws IllegalArgumentException if duplicate keys are provided
   */
  public static <K, V> ImmutableMap<K, V> of(
      K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
    checkEntryNotNull(k1, v1);
    checkEntryNotNull(k2, v2);
    checkEntryNotNull(k3, v3);
    checkEntryNotNull(k4, v4);
    checkEntryNotNull(k5, v5);
    return RegularImmutableMap.create(5, new Object[] {k1, v1, k2, v2, k3, v3, k4, v4, k5, v5});
  }

  // looking for of() with > 5 entries? Use the builder instead.

  /**
   * Verifies that {@code key} and {@code value} are non-null, and returns a new immutable entry
   * with those values.
   *
   *
A call to {@link Entry#setValue} on the returned entry will always throw {@link
   * UnsupportedOperationException}.
   */
  static <K, V> Entry<K, V> entryOf(K key, V value) {
    checkEntryNotNull(key, value);
    return new AbstractMap.SimpleImmutableEntry<>(key, value);
  }

  /**
   * Returns a new builder. The generated builder is equivalent to the builder created by the {@link
   * Builder} constructor.
   */
  public static <K, V> Builder<K, V> builder() {
    return new Builder<>();
  }

  /**
   * Returns a new builder, expecting the specified number of entries to be added.
   *
   *
If {@code expectedSize} is exactly the number of entries added to the builder before {@link
   * Builder#build} is called, the builder is likely to perform better than an unsized {@link
   * #builder()} would have.
   *
   *
It is not specified if any performance benefits apply if {@code expectedSize} is close to,
   * but not exactly, the number of entries added to the builder.
   *
   * @since 23.1
   */
  @Beta
  public static <K, V> Builder<K, V> builderWithExpectedSize(int expectedSize) {
    checkNonnegative(expectedSize, "expectedSize");
    return new Builder<>(expectedSize);
  }

  static void checkNoConflict(
      boolean safe, String conflictDescription, Entry<?, ?> entry1, Entry<?, ?> entry2) {
    if (!safe) {
      throw conflictException(conflictDescription, entry1, entry2);
    }
  }

  static IllegalArgumentException conflictException(
      String conflictDescription, Object entry1, Object entry2) {
    return new IllegalArgumentException(
        "Multiple entries with same " + conflictDescription + ": " + entry1 + " and " + entry2);
  }

  /**
   * A builder for creating immutable map instances, especially {@code public static final} maps
   * ("constant maps"). Example:
   *
   *
{@code
   * static final ImmutableMap<String, Integer> WORD_TO_INT =
   *     new ImmutableMap.Builder<String, Integer>()
   *         .put("one", 1)
   *         .put("two", 2)
   *         .put("three", 3)
   *         .build();
   * }

   *
   *
For small immutable maps, the {@code ImmutableMap.of()} methods are even more
   * convenient.
   *
   *
By default, a {@code Builder} will generate maps that iterate over entries in the order they
   * were inserted into the builder, equivalently to {@code LinkedHashMap}. For example, in the
   * above example, {@code WORD_TO_INT.entrySet()} is guaranteed to iterate over the entries in the
   * order {@code "one"=1, "two"=2, "three"=3}, and {@code keySet()} and {@code values()} respect
   * the same order. If you want a different order, consider using {@link ImmutableSortedMap} to
   * sort by keys, or call {@link #orderEntriesByValue(Comparator)}, which changes this builder to
   * sort entries by value.
   *
   *
Builder instances can be reused - it is safe to call {@link #build} multiple times to build
   * multiple maps in series. Each map is a superset of the maps created before it.
   *
   * @since 2.0
   */
  public static class Builder<K, V> {
    @MonotonicNonNullDecl Comparator<? super V> valueComparator;
    Object[] alternatingKeysAndValues;
    int size;
    boolean entriesUsed;

    /**
     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
     * ImmutableMap#builder}.
     */
    public Builder() {
      this(ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY);
    }

    @SuppressWarnings("unchecked")
    Builder(int initialCapacity) {
      this.alternatingKeysAndValues = new Object[2 * initialCapacity];
      this.size = 0;
      this.entriesUsed = false;
    }

    private void ensureCapacity(int minCapacity) {
      if (minCapacity * 2 > alternatingKeysAndValues.length) {
        alternatingKeysAndValues =
            Arrays.copyOf(
                alternatingKeysAndValues,
                ImmutableCollection.Builder.expandedCapacity(
                    alternatingKeysAndValues.length, minCapacity * 2));
        entriesUsed = false;
      }
    }

    /**
     * Associates {@code key} with {@code value} in the built map. Duplicate keys are not allowed,
     * and will cause {@link #build} to fail.
     */
    @CanIgnoreReturnValue
    public Builder<K, V> put(K key, V value) {
      ensureCapacity(size + 1);
      checkEntryNotNull(key, value);
      alternatingKeysAndValues[2 * size] = key;
      alternatingKeysAndValues[2 * size + 1] = value;
      size++;
      return this;
    }

    /**
     * Adds the given {@code entry} to the map, making it immutable if necessary. Duplicate keys are
     * not allowed, and will cause {@link #build} to fail.
     *
     * @since 11.0
     */
    @CanIgnoreReturnValue
    public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
      return put(entry.getKey(), entry.getValue());
    }

    /**
     * Associates all of the given map's keys and values in the built map. Duplicate keys are not
     * allowed, and will cause {@link #build} to fail.
     *
     * @throws NullPointerException if any key or value in {@code map} is null
     */
    @CanIgnoreReturnValue
    public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
      return putAll(map.entrySet());
    }

    /**
     * Adds all of the given entries to the built map. Duplicate keys are not allowed, and will
     * cause {@link #build} to fail.
     *
     * @throws NullPointerException if any key, value, or entry is null
     * @since 19.0
     */
    @CanIgnoreReturnValue
    @Beta
    public Builder<K, V> putAll(Iterable<? extends Entry<? extends K, ? extends V>> entries) {
      if (entries instanceof Collection) {
        ensureCapacity(size + ((Collection<?>) entries).size());
      }
      for (Entry<? extends K, ? extends V> entry : entries) {
        put(entry);
      }
      return this;
    }

    /**
     * Configures this {@code Builder} to order entries by value according to the specified
     * comparator.
     *
     *
The sort order is stable, that is, if two entries have values that compare as equivalent,
     * the entry that was inserted first will be first in the built map's iteration order.
     *
     * @throws IllegalStateException if this method was already called
     * @since 19.0
     */
    @CanIgnoreReturnValue
    @Beta
    public Builder<K, V> orderEntriesByValue(Comparator<? super V> valueComparator) {
      checkState(this.valueComparator == null, "valueComparator was already set");
      this.valueComparator = checkNotNull(valueComparator, "valueComparator");
      return this;
    }

    /*
     * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap
     * versions throw an IllegalStateException instead?
     */

    /**
     * Returns a newly-created immutable map. The iteration order of the returned map is the order
     * in which entries were inserted into the builder, unless {@link #orderEntriesByValue} was
     * called, in which case entries are sorted by value.
     *
     * @throws IllegalArgumentException if duplicate keys were added
     */
    @SuppressWarnings("unchecked")
    public ImmutableMap<K, V> build() {
      /*
       * If entries is full, then this implementation may end up using the entries array
       * directly and writing over the entry objects with non-terminal entries, but this is
       * safe; if this Builder is used further, it will grow the entries array (so it can't
       * affect the original array), and future build() calls will always copy any entry
       * objects that cannot be safely reused.
       */
      sortEntries();
      entriesUsed = true;
      return RegularImmutableMap.create(size, alternatingKeysAndValues);
    }

    void sortEntries() {
      if (valueComparator != null) {
        if (entriesUsed) {
          alternatingKeysAndValues = Arrays.copyOf(alternatingKeysAndValues, 2 * size);
        }
        Entry<K, V>[] entries = new Entry[size];
        for (int i = 0; i < size; i++) {
          entries[i] =
              new AbstractMap.SimpleImmutableEntry<K, V>(
                  (K) alternatingKeysAndValues[2 * i], (V) alternatingKeysAndValues[2 * i + 1]);
        }
        Arrays.sort(
            entries, 0, size, Ordering.from(valueComparator).onResultOf(Maps.<V>valueFunction()));
        for (int i = 0; i < size; i++) {
          alternatingKeysAndValues[2 * i] = entries[i].getKey();
          alternatingKeysAndValues[2 * i + 1] = entries[i].getValue();
        }
      }
    }
  }

  /**
   * Returns an immutable map containing the same entries as {@code map}. The returned map iterates
   * over entries in the same order as the {@code entrySet} of the original map. If {@code map}
   * somehow contains entries with duplicate keys (for example, if it is a {@code SortedMap} whose
   * comparator is not consistent with equals), the results of this method are undefined.
   *
   *
Despite the method name, this method attempts to avoid actually copying the data when it is
   * safe to do so. The exact circumstances under which a copy will or will not be performed are
   * undocumented and subject to change.
   *
   * @throws NullPointerException if any key or value in {@code map} is null
   */
  public static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V> map) {
    if ((map instanceof ImmutableMap) && !(map instanceof SortedMap)) {
      @SuppressWarnings("unchecked") // safe since map is not writable
      ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
      if (!kvMap.isPartialView()) {
        return kvMap;
      }
    }
    return copyOf(map.entrySet());
  }

  /**
   * Returns an immutable map containing the specified entries. The returned map iterates over
   * entries in the same order as the original iterable.
   *
   * @throws NullPointerException if any key, value, or entry is null
   * @throws IllegalArgumentException if two entries have the same key
   * @since 19.0
   */
  @Beta
  public static <K, V> ImmutableMap<K, V> copyOf(
      Iterable<? extends Entry<? extends K, ? extends V>> entries) {
    int initialCapacity =
        (entries instanceof Collection)
            ? ((Collection<?>) entries).size()
            : ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY;
    ImmutableMap.Builder<K, V> builder = new ImmutableMap.Builder<K, V>(initialCapacity);
    builder.putAll(entries);
    return builder.build();
  }

  static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];

  abstract static class IteratorBasedImmutableMap<K, V> extends ImmutableMap<K, V> {
    abstract UnmodifiableIterator<Entry<K, V>> entryIterator();

    @Override
    ImmutableSet<K> createKeySet() {
      return new ImmutableMapKeySet<>(this);
    }

    @Override
    ImmutableSet<Entry<K, V>> createEntrySet() {
      class EntrySetImpl extends ImmutableMapEntrySet<K, V> {
        @Override
        ImmutableMap<K, V> map() {
          return IteratorBasedImmutableMap.this;
        }

        @Override
        public UnmodifiableIterator<Entry<K, V>> iterator() {
          return entryIterator();
        }
      }
      return new EntrySetImpl();
    }

    @Override
    ImmutableCollection<V> createValues() {
      return new ImmutableMapValues<>(this);
    }
  }

  ImmutableMap() {}

  /**
   * Guaranteed to throw an exception and leave the map unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final V put(K k, V v) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the map unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final V remove(Object o) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the map unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @Deprecated
  @Override
  public final void putAll(Map<? extends K, ? extends V> map) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the map unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @Deprecated
  @Override
  public final void clear() {
    throw new UnsupportedOperationException();
  }

  @Override
  public boolean isEmpty() {
    return size() == 0;
  }

  @Override
  public boolean containsKey(@NullableDecl Object key) {
    return get(key) != null;
  }

  @Override
  public boolean containsValue(@NullableDecl Object value) {
    return values().contains(value);
  }

  // Overriding to mark it Nullable
  @Override
  public abstract V get(@NullableDecl Object key);

  /**
   * {@inheritDoc}
   *
   *
See {@code
   * Map.getOrDefault}.
   *
   * @since 23.5 (but since 21.0 in the JRE flavor).
   *     Note that API Level 24 users can call this method with any version of Guava.
   */
  // @Override under Java 8 / API Level 24
  public final V getOrDefault(@NullableDecl Object key, @NullableDecl V defaultValue) {
    V result = get(key);
    return (result != null) ? result : defaultValue;
  }

  @LazyInit @RetainedWith private transient ImmutableSet<Entry<K, V>> entrySet;

  /**
   * Returns an immutable set of the mappings in this map. The iteration order is specified by the
   * method used to create this map. Typically, this is insertion order.
   */
  @Override
  public ImmutableSet<Entry<K, V>> entrySet() {
    ImmutableSet<Entry<K, V>> result = entrySet;
    return (result == null) ? entrySet = createEntrySet() : result;
  }

  abstract ImmutableSet<Entry<K, V>> createEntrySet();

  @LazyInit @RetainedWith private transient ImmutableSet<K> keySet;

  /**
   * Returns an immutable set of the keys in this map, in the same order that they appear in {@link
   * #entrySet}.
   */
  @Override
  public ImmutableSet<K> keySet() {
    ImmutableSet<K> result = keySet;
    return (result == null) ? keySet = createKeySet() : result;
  }

  /*
   * This could have a good default implementation of return new ImmutableKeySet<K, V>(this),
   * but ProGuard can't figure out how to eliminate that default when RegularImmutableMap
   * overrides it.
   */
  abstract ImmutableSet<K> createKeySet();

  UnmodifiableIterator<K> keyIterator() {
    final UnmodifiableIterator<Entry<K, V>> entryIterator = entrySet().iterator();
    return new UnmodifiableIterator<K>() {
      @Override
      public boolean hasNext() {
        return entryIterator.hasNext();
      }

      @Override
      public K next() {
        return entryIterator.next().getKey();
      }
    };
  }

  @LazyInit @RetainedWith private transient ImmutableCollection<V> values;

  /**
   * Returns an immutable collection of the values in this map, in the same order that they appear
   * in {@link #entrySet}.
   */
  @Override
  public ImmutableCollection<V> values() {
    ImmutableCollection<V> result = values;
    return (result == null) ? values = createValues() : result;
  }

  /*
   * This could have a good default implementation of {@code return new
   * ImmutableMapValues<K, V>(this)}, but ProGuard can't figure out how to eliminate that default
   * when RegularImmutableMap overrides it.
   */
  abstract ImmutableCollection<V> createValues();

  // cached so that this.multimapView().inverse() only computes inverse once
  @LazyInit private transient ImmutableSetMultimap<K, V> multimapView;

  /**
   * Returns a multimap view of the map.
   *
   * @since 14.0
   */
  public ImmutableSetMultimap<K, V> asMultimap() {
    if (isEmpty()) {
      return ImmutableSetMultimap.of();
    }
    ImmutableSetMultimap<K, V> result = multimapView;
    return (result == null)
        ? (multimapView =
            new ImmutableSetMultimap<>(new MapViewOfValuesAsSingletonSets(), size(), null))
        : result;
  }

  @WeakOuter
  private final class MapViewOfValuesAsSingletonSets
      extends IteratorBasedImmutableMap<K, ImmutableSet<V>> {

    @Override
    public int size() {
      return ImmutableMap.this.size();
    }

    @Override
    ImmutableSet<K> createKeySet() {
      return ImmutableMap.this.keySet();
    }

    @Override
    public boolean containsKey(@NullableDecl Object key) {
      return ImmutableMap.this.containsKey(key);
    }

    @Override
    public ImmutableSet<V> get(@NullableDecl Object key) {
      V outerValue = ImmutableMap.this.get(key);
      return (outerValue == null) ? null : ImmutableSet.of(outerValue);
    }

    @Override
    boolean isPartialView() {
      return ImmutableMap.this.isPartialView();
    }

    @Override
    public int hashCode() {
      // ImmutableSet.of(value).hashCode() == value.hashCode(), so the hashes are the same
      return ImmutableMap.this.hashCode();
    }

    @Override
    boolean isHashCodeFast() {
      return ImmutableMap.this.isHashCodeFast();
    }

    @Override
    UnmodifiableIterator<Entry<K, ImmutableSet<V>>> entryIterator() {
      final Iterator<Entry<K, V>> backingIterator = ImmutableMap.this.entrySet().iterator();
      return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
        @Override
        public boolean hasNext() {
          return backingIterator.hasNext();
        }

        @Override
        public Entry<K, ImmutableSet<V>> next() {
          final Entry<K, V> backingEntry = backingIterator.next();
          return new AbstractMapEntry<K, ImmutableSet<V>>() {
            @Override
            public K getKey() {
              return backingEntry.getKey();
            }

            @Override
            public ImmutableSet<V> getValue() {
              return ImmutableSet.of(backingEntry.getValue());
            }
          };
        }
      };
    }
  }

  @Override
  public boolean equals(@NullableDecl Object object) {
    return Maps.equalsImpl(this, object);
  }

  abstract boolean isPartialView();

  @Override
  public int hashCode() {
    return Sets.hashCodeImpl(entrySet());
  }

  boolean isHashCodeFast() {
    return false;
  }

  @Override
  public String toString() {
    return Maps.toStringImpl(this);
  }

  /**
   * Serialized type for all ImmutableMap instances. It captures the logical contents and they are
   * reconstructed using public factory methods. This ensures that the implementation types remain
   * as implementation details.
   */
  static class SerializedForm implements Serializable {
    private final Object[] keys;
    private final Object[] values;

    SerializedForm(ImmutableMap<?, ?> map) {
      keys = new Object[map.size()];
      values = new Object[map.size()];
      int i = 0;
      for (Entry<?, ?> entry : map.entrySet()) {
        keys[i] = entry.getKey();
        values[i] = entry.getValue();
        i++;
      }
    }

    Object readResolve() {
      Builder<Object, Object> builder = new Builder<>(keys.length);
      return createMap(builder);
    }

    Object createMap(Builder<Object, Object> builder) {
      for (int i = 0; i < keys.length; i++) {
        builder.put(keys[i], values[i]);
      }
      return builder.build();
    }

    private static final long serialVersionUID = 0;
  }

  Object writeReplace() {
    return new SerializedForm(this);
  }
}


/*
 * Copyright (C) 2008 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
import static com.google.common.collect.ObjectArrays.checkElementsNotNull;

import com.google.common.annotations.GwtCompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * A {@link Collection} whose contents will never change, and which offers a few additional
 * guarantees detailed below.
 *
 *
Warning: avoid direct usage of {@link ImmutableCollection} as a type (just as
 * with {@link Collection} itself). Prefer subtypes such as {@link ImmutableSet} or {@link
 * ImmutableList}, which have well-defined {@link #equals} semantics, thus avoiding a common source
 * of bugs and confusion.
 *
 *
About all {@code Immutable-} collections

 *
 *
The remainder of this documentation applies to every public {@code Immutable-} type in this
 * package, whether it is a subtype of {@code ImmutableCollection} or not.
 *
 *
Guarantees

 *
 *
Each makes the following guarantees:
 *
 *

 *
Shallow immutability. Elements can never be added, removed or replaced in this
 *       collection. This is a stronger guarantee than that of {@link
 *       Collections#unmodifiableCollection}, whose contents change whenever the wrapped collection
 *       is modified.
 *
Null-hostility. This collection will never contain a null element.
 *
Deterministic iteration. The iteration order is always well-defined, depending on
 *       how the collection was created. Typically this is insertion order unless an explicit
 *       ordering is otherwise specified (e.g. {@link ImmutableSortedSet#naturalOrder}). See the
 *       appropriate factory method for details. View collections such as {@link
 *       ImmutableMultiset#elementSet} iterate in the same order as the parent, except as noted.
 *
Thread safety. It is safe to access this collection concurrently from multiple
 *       threads.
 *
Integrity. This type cannot be subclassed outside this package (which would allow
 *       these guarantees to be violated).
 *

 *
 *
"Interfaces", not implementations

 *
 *
These are classes instead of interfaces to prevent external subtyping, but should be thought
 * of as interfaces in every important sense. Each public class such as {@link ImmutableSet} is a
 * type offering meaningful behavioral guarantees. This is substantially different from the
 * case of (say) {@link HashSet}, which is an implementation, with semantics that were
 * largely defined by its supertype.
 *
 *
For field types and method return types, you should generally use the immutable type (such as
 * {@link ImmutableList}) instead of the general collection interface type (such as {@link List}).
 * This communicates to your callers all of the semantic guarantees listed above, which is almost
 * always very useful information.
 *
 *
On the other hand, a parameter type of {@link ImmutableList} is generally a nuisance to
 * callers. Instead, accept {@link Iterable} and have your method or constructor body pass it to the
 * appropriate {@code copyOf} method itself.
 *
 *
Expressing the immutability guarantee directly in the type that user code references is a
 * powerful advantage. Although Java offers certain immutable collection factory methods, such as
 * {@link Collections#singleton(Object)} and {@code Set.of},
 * we recommend using these classes instead for this reason (as well as for consistency).
 *
 *
Creation

 *
 *
Except for logically "abstract" types like {@code ImmutableCollection} itself, each {@code
 * Immutable} type provides the static operations you need to obtain instances of that type. These
 * usually include:
 *
 *

 *
Static methods named {@code of}, accepting an explicit list of elements or entries.
 *
Static methods named {@code copyOf} (or {@code copyOfSorted}), accepting an existing
 *       collection whose contents should be copied.
 *
A static nested {@code Builder} class which can be used to populate a new immutable
 *       instance.
 *

 *
 *
Warnings

 *
 *

 *
Warning: as with any collection, it is almost always a bad idea to modify an element
 *       (in a way that affects its {@link Object#equals} behavior) while it is contained in a
 *       collection. Undefined behavior and bugs will result. It's generally best to avoid using
 *       mutable objects as elements at all, as many users may expect your "immutable" object to be
 *       deeply immutable.
 *

 *
 *
Performance notes

 *
 *

 *
Implementations can be generally assumed to prioritize memory efficiency, then speed of
 *       access, and lastly speed of creation.
 *
The {@code copyOf} methods will sometimes recognize that the actual copy operation is
 *       unnecessary; for example, {@code copyOf(copyOf(anArrayList))} should copy the data only
 *       once. This reduces the expense of habitually making defensive copies at API boundaries.
 *       However, the precise conditions for skipping the copy operation are undefined.
 *
Warning: a view collection such as {@link ImmutableMap#keySet} or {@link
 *       ImmutableList#subList} may retain a reference to the entire data set, preventing it from
 *       being garbage collected. If some of the data is no longer reachable through other means,
 *       this constitutes a memory leak. Pass the view collection to the appropriate {@code copyOf}
 *       method to obtain a correctly-sized copy.
 *
The performance of using the associated {@code Builder} class can be assumed to be no
 *       worse, and possibly better, than creating a mutable collection and copying it.
 *
Implementations generally do not cache hash codes. If your element or key type has a slow
 *       {@code hashCode} implementation, it should cache it itself.
 *

 *
 *
Example usage

 *
 *
{@code
 * class Foo {
 *   private static final ImmutableSet<String> RESERVED_CODES =
 *       ImmutableSet.of("AZ", "CQ", "ZX");
 *
 *   private final ImmutableSet<String> codes;
 *
 *   public Foo(Iterable<String> codes) {
 *     this.codes = ImmutableSet.copyOf(codes);
 *     checkArgument(Collections.disjoint(this.codes, RESERVED_CODES));
 *   }
 * }
 * }

 *
 *
See also

 *
 *
See the Guava User Guide article on  immutable collections.
 *
 * @since 2.0
 */
@GwtCompatible(emulated = true)
@SuppressWarnings("serial") // we're overriding default serialization
// TODO(kevinb): I think we should push everything down to "BaseImmutableCollection" or something,
// just to do everything we can to emphasize the "practically an interface" nature of this class.
public abstract class ImmutableCollection<E> extends AbstractCollection<E> implements Serializable {

  ImmutableCollection() {}

  /** Returns an unmodifiable iterator across the elements in this collection. */
  @Override
  public abstract UnmodifiableIterator<E> iterator();

  private static final Object[] EMPTY_ARRAY = {};

  @Override
  public final Object[] toArray() {
    return toArray(EMPTY_ARRAY);
  }

  @CanIgnoreReturnValue
  @Override
  public final <T> T[] toArray(T[] other) {
    checkNotNull(other);
    int size = size();

    if (other.length < size) {
      Object[] internal = internalArray();
      if (internal != null) {
        return Platform.copy(internal, internalArrayStart(), internalArrayEnd(), other);
      }
      other = ObjectArrays.newArray(other, size);
    } else if (other.length > size) {
      other[size] = null;
    }
    copyIntoArray(other, 0);
    return other;
  }

  /** If this collection is backed by an array of its elements in insertion order, returns it. */
  Object[] internalArray() {
    return null;
  }

  /**
   * If this collection is backed by an array of its elements in insertion order, returns the offset
   * where this collection's elements start.
   */
  int internalArrayStart() {
    throw new UnsupportedOperationException();
  }

  /**
   * If this collection is backed by an array of its elements in insertion order, returns the offset
   * where this collection's elements end.
   */
  int internalArrayEnd() {
    throw new UnsupportedOperationException();
  }

  @Override
  public abstract boolean contains(@NullableDecl Object object);

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final boolean add(E e) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final boolean remove(Object object) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final boolean addAll(Collection<? extends E> newElements) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final boolean removeAll(Collection<?> oldElements) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @CanIgnoreReturnValue
  @Deprecated
  @Override
  public final boolean retainAll(Collection<?> elementsToKeep) {
    throw new UnsupportedOperationException();
  }

  /**
   * Guaranteed to throw an exception and leave the collection unmodified.
   *
   * @throws UnsupportedOperationException always
   * @deprecated Unsupported operation.
   */
  @Deprecated
  @Override
  public final void clear() {
    throw new UnsupportedOperationException();
  }

  /**
   * Returns an {@code ImmutableList} containing the same elements, in the same order, as this
   * collection.
   *
   *
Performance note: in most cases this method can return quickly without actually
   * copying anything. The exact circumstances under which the copy is performed are undefined and
   * subject to change.
   *
   * @since 2.0
   */
  public ImmutableList<E> asList() {
    return isEmpty() ? ImmutableList.<E>of() : ImmutableList.<E>asImmutableList(toArray());
  }

  /**
   * Returns {@code true} if this immutable collection's implementation contains references to
   * user-created objects that aren't accessible via this collection's methods. This is generally
   * used to determine whether {@code copyOf} implementations should make an explicit copy to avoid
   * memory leaks.
   */
  abstract boolean isPartialView();

  /**
   * Copies the contents of this immutable collection into the specified array at the specified
   * offset. Returns {@code offset + size()}.
   */
  @CanIgnoreReturnValue
  int copyIntoArray(Object[] dst, int offset) {
    for (E e : this) {
      dst[offset++] = e;
    }
    return offset;
  }

  Object writeReplace() {
    // We serialize by default to ImmutableList, the simplest thing that works.
    return new ImmutableList.SerializedForm(toArray());
  }

  /**
   * Abstract base class for builders of {@link ImmutableCollection} types.
   *
   * @since 10.0
   */
  public abstract static class Builder<E> {
    static final int DEFAULT_INITIAL_CAPACITY = 4;

    static int expandedCapacity(int oldCapacity, int minCapacity) {
      if (minCapacity < 0) {
        throw new AssertionError("cannot store more than MAX_VALUE elements");
      }
      // careful of overflow!
      int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
      if (newCapacity < minCapacity) {
        newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
      }
      if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
        // guaranteed to be >= newCapacity
      }
      return newCapacity;
    }

    Builder() {}

    /**
     * Adds {@code element} to the {@code ImmutableCollection} being built.
     *
     *
Note that each builder class covariantly returns its own type from this method.
     *
     * @param element the element to add
     * @return this {@code Builder} instance
     * @throws NullPointerException if {@code element} is null
     */
    @CanIgnoreReturnValue
    public abstract Builder<E> add(E element);

    /**
     * Adds each element of {@code elements} to the {@code ImmutableCollection} being built.
     *
     *
Note that each builder class overrides this method in order to covariantly return its own
     * type.
     *
     * @param elements the elements to add
     * @return this {@code Builder} instance
     * @throws NullPointerException if {@code elements} is null or contains a null element
     */
    @CanIgnoreReturnValue
    public Builder<E> add(E... elements) {
      for (E element : elements) {
        add(element);
      }
      return this;
    }

    /**
     * Adds each element of {@code elements} to the {@code ImmutableCollection} being built.
     *
     *
Note that each builder class overrides this method in order to covariantly return its own
     * type.
     *
     * @param elements the elements to add
     * @return this {@code Builder} instance
     * @throws NullPointerException if {@code elements} is null or contains a null element
     */
    @CanIgnoreReturnValue
    public Builder<E> addAll(Iterable<? extends E> elements) {
      for (E element : elements) {
        add(element);
      }
      return this;
    }

    /**
     * Adds each element of {@code elements} to the {@code ImmutableCollection} being built.
     *
     *
Note that each builder class overrides this method in order to covariantly return its own
     * type.
     *
     * @param elements the elements to add
     * @return this {@code Builder} instance
     * @throws NullPointerException if {@code elements} is null or contains a null element
     */
    @CanIgnoreReturnValue
    public Builder<E> addAll(Iterator<? extends E> elements) {
      while (elements.hasNext()) {
        add(elements.next());
      }
      return this;
    }

    /**
     * Returns a newly-created {@code ImmutableCollection} of the appropriate type, containing the
     * elements provided to this builder.
     *
     *
Note that each builder class covariantly returns the appropriate type of {@code
     * ImmutableCollection} from this method.
     */
    public abstract ImmutableCollection<E> build();
  }

  abstract static class ArrayBasedBuilder<E> extends ImmutableCollection.Builder<E> {
    Object[] contents;
    int size;
    boolean forceCopy;

    ArrayBasedBuilder(int initialCapacity) {
      checkNonnegative(initialCapacity, "initialCapacity");
      this.contents = new Object[initialCapacity];
      this.size = 0;
    }

    /*
     * Expand the absolute capacity of the builder so it can accept at least the specified number of
     * elements without being resized. Also, if we've already built a collection backed by the
     * current array, create a new array.
     */
    private void getReadyToExpandTo(int minCapacity) {
      if (contents.length < minCapacity) {
        this.contents =
            Arrays.copyOf(this.contents, expandedCapacity(contents.length, minCapacity));
        forceCopy = false;
      } else if (forceCopy) {
        this.contents = contents.clone();
        forceCopy = false;
      }
    }

    @CanIgnoreReturnValue
    @Override
    public ArrayBasedBuilder<E> add(E element) {
      checkNotNull(element);
      getReadyToExpandTo(size + 1);
      contents[size++] = element;
      return this;
    }

    @CanIgnoreReturnValue
    @Override
    public Builder<E> add(E... elements) {
      checkElementsNotNull(elements);
      getReadyToExpandTo(size + elements.length);
      System.arraycopy(elements, 0, contents, size, elements.length);
      size += elements.length;
      return this;
    }

    @CanIgnoreReturnValue
    @Override
    public Builder<E> addAll(Iterable<? extends E> elements) {
      if (elements instanceof Collection) {
        Collection<?> collection = (Collection<?>) elements;
        getReadyToExpandTo(size + collection.size());
        if (collection instanceof ImmutableCollection) {
          ImmutableCollection<?> immutableCollection = (ImmutableCollection<?>) collection;
          size = immutableCollection.copyIntoArray(contents, size);
          return this;
        }
      }
      super.addAll(elements);
      return this;
    }
  }
}


/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import com.google.common.annotations.GwtCompatible;

/**
 * A {@code Multiset} implementation with predictable iteration order. Its iterator orders elements
 * according to when the first occurrence of the element was added. When the multiset contains
 * multiple instances of an element, those instances are consecutive in the iteration order. If all
 * occurrences of an element are removed, after which that element is added to the multiset, the
 * element will appear at the end of the iteration.
 *
 *
See the Guava User Guide article on  {@code
 * Multiset}.
 *
 * @author Kevin Bourrillion
 * @author Jared Levy
 * @since 2.0
 */
@GwtCompatible(serializable = true, emulated = true)
public final class LinkedHashMultiset<E> extends AbstractMapBasedMultiset<E> {

  /** Creates a new, empty {@code LinkedHashMultiset} using the default initial capacity. */
  public static <E> LinkedHashMultiset<E> create() {
    return create(ObjectCountHashMap.DEFAULT_SIZE);
  }

  /**
   * Creates a new, empty {@code LinkedHashMultiset} with the specified expected number of distinct
   * elements.
   *
   * @param distinctElements the expected number of distinct elements
   * @throws IllegalArgumentException if {@code distinctElements} is negative
   */
  public static <E> LinkedHashMultiset<E> create(int distinctElements) {
    return new LinkedHashMultiset<E>(distinctElements);
  }

  /**
   * Creates a new {@code LinkedHashMultiset} containing the specified elements.
   *
   *
This implementation is highly efficient when {@code elements} is itself a {@link Multiset}.
   *
   * @param elements the elements that the multiset should contain
   */
  public static <E> LinkedHashMultiset<E> create(Iterable<? extends E> elements) {
    LinkedHashMultiset<E> multiset = create(Multisets.inferDistinctElements(elements));
    Iterables.addAll(multiset, elements);
    return multiset;
  }

  LinkedHashMultiset(int distinctElements) {
    super(distinctElements);
  }

  @Override
  void init(int distinctElements) {
    backingMap = new ObjectCountLinkedHashMap<>(distinctElements);
  }
}