/*
 * 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.base;

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

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a
 * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns
 * them as a {@link String}. Example:
 *
 *
{@code
 * Joiner joiner = Joiner.on("; ").skipNulls();
 *  . . .
 * return joiner.join("Harry", null, "Ron", "Hermione");
 * }

 *
 *
This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are
 * converted to strings using {@link Object#toString()} before being appended.
 *
 *
If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining
 * methods will throw {@link NullPointerException} if any given element is null.
 *
 *
Warning: joiner instances are always immutable; a configuration method such as {@code
 * useForNull} has no effect on the instance it is invoked on! You must store and use the new joiner
 * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code
 * static final} constants.
 *
 *
{@code
 * // Bad! Do not do this!
 * Joiner joiner = Joiner.on(',');
 * joiner.skipNulls(); // does nothing!
 * return joiner.join("wrong", null, "wrong");
 * }

 *
 *
See the Guava User Guide article on {@code Joiner}.
 *
 * @author Kevin Bourrillion
 * @since 2.0
 */
@GwtCompatible
public class Joiner {
  /** Returns a joiner which automatically places {@code separator} between consecutive elements. */
  public static Joiner on(String separator) {
    return new Joiner(separator);
  }

  /** Returns a joiner which automatically places {@code separator} between consecutive elements. */
  public static Joiner on(char separator) {
    return new Joiner(String.valueOf(separator));
  }

  private final String separator;

  private Joiner(String separator) {
    this.separator = checkNotNull(separator);
  }

  private Joiner(Joiner prototype) {
    this.separator = prototype.separator;
  }

  /**
   * Appends the string representation of each of {@code parts}, using the previously configured
   * separator between each, to {@code appendable}.
   */
  @CanIgnoreReturnValue
  public  A appendTo(A appendable, Iterable<?> parts) throws IOException {
    return appendTo(appendable, parts.iterator());
  }

  /**
   * Appends the string representation of each of {@code parts}, using the previously configured
   * separator between each, to {@code appendable}.
   *
   * @since 11.0
   */
  @CanIgnoreReturnValue
  public  A appendTo(A appendable, Iterator<?> parts) throws IOException {
    checkNotNull(appendable);
    if (parts.hasNext()) {
      appendable.append(toString(parts.next()));
      while (parts.hasNext()) {
        appendable.append(separator);
        appendable.append(toString(parts.next()));
      }
    }
    return appendable;
  }

  /**
   * Appends the string representation of each of {@code parts}, using the previously configured
   * separator between each, to {@code appendable}.
   */
  @CanIgnoreReturnValue
  public final  A appendTo(A appendable, Object[] parts) throws IOException {
    return appendTo(appendable, Arrays.asList(parts));
  }

  /** Appends to {@code appendable} the string representation of each of the remaining arguments. */
  @CanIgnoreReturnValue
  public final  A appendTo(
      A appendable, @Nullable Object first, @Nullable Object second, Object... rest)
      throws IOException {
    return appendTo(appendable, iterable(first, second, rest));
  }

  /**
   * Appends the string representation of each of {@code parts}, using the previously configured
   * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
   * Iterable)}, except that it does not throw {@link IOException}.
   */
  @CanIgnoreReturnValue
  public final StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) {
    return appendTo(builder, parts.iterator());
  }

  /**
   * Appends the string representation of each of {@code parts}, using the previously configured
   * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
   * Iterable)}, except that it does not throw {@link IOException}.
   *
   * @since 11.0
   */
  @CanIgnoreReturnValue
  public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
    try {
      appendTo((Appendable) builder, parts);
    } catch (IOException impossible) {
      throw new AssertionError(impossible);
    }
    return builder;
  }

  /**
   * Appends the string representation of each of {@code parts}, using the previously configured
   * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
   * Iterable)}, except that it does not throw {@link IOException}.
   */
  @CanIgnoreReturnValue
  public final StringBuilder appendTo(StringBuilder builder, Object[] parts) {
    return appendTo(builder, Arrays.asList(parts));
  }

  /**
   * Appends to {@code builder} the string representation of each of the remaining arguments.
   * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not
   * throw {@link IOException}.
   */
  @CanIgnoreReturnValue
  public final StringBuilder appendTo(
      StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) {
    return appendTo(builder, iterable(first, second, rest));
  }

  /**
   * Returns a string containing the string representation of each of {@code parts}, using the
   * previously configured separator between each.
   */
  public final String join(Iterable<?> parts) {
    return join(parts.iterator());
  }

  /**
   * Returns a string containing the string representation of each of {@code parts}, using the
   * previously configured separator between each.
   *
   * @since 11.0
   */
  public final String join(Iterator<?> parts) {
    return appendTo(new StringBuilder(), parts).toString();
  }

  /**
   * Returns a string containing the string representation of each of {@code parts}, using the
   * previously configured separator between each.
   */
  public final String join(Object[] parts) {
    return join(Arrays.asList(parts));
  }

  /**
   * Returns a string containing the string representation of each argument, using the previously
   * configured separator between each.
   */
  public final String join(@Nullable Object first, @Nullable Object second, Object... rest) {
    return join(iterable(first, second, rest));
  }

  /**
   * Returns a joiner with the same behavior as this one, except automatically substituting {@code
   * nullText} for any provided null elements.
   */
  public Joiner useForNull(final String nullText) {
    checkNotNull(nullText);
    return new Joiner(this) {
      @Override
      CharSequence toString(@Nullable Object part) {
        return (part == null) ? nullText : Joiner.this.toString(part);
      }

      @Override
      public Joiner useForNull(String nullText) {
        throw new UnsupportedOperationException("already specified useForNull");
      }

      @Override
      public Joiner skipNulls() {
        throw new UnsupportedOperationException("already specified useForNull");
      }
    };
  }

  /**
   * Returns a joiner with the same behavior as this joiner, except automatically skipping over any
   * provided null elements.
   */
  public Joiner skipNulls() {
    return new Joiner(this) {
      @Override
      public  A appendTo(A appendable, Iterator<?> parts) throws IOException {
        checkNotNull(appendable, "appendable");
        checkNotNull(parts, "parts");
        while (parts.hasNext()) {
          Object part = parts.next();
          if (part != null) {
            appendable.append(Joiner.this.toString(part));
            break;
          }
        }
        while (parts.hasNext()) {
          Object part = parts.next();
          if (part != null) {
            appendable.append(separator);
            appendable.append(Joiner.this.toString(part));
          }
        }
        return appendable;
      }

      @Override
      public Joiner useForNull(String nullText) {
        throw new UnsupportedOperationException("already specified skipNulls");
      }

      @Override
      public MapJoiner withKeyValueSeparator(String kvs) {
        throw new UnsupportedOperationException("can't use .skipNulls() with maps");
      }
    };
  }

  /**
   * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
   * this {@code Joiner} otherwise.
   *
   * @since 20.0
   */
  public MapJoiner withKeyValueSeparator(char keyValueSeparator) {
    return withKeyValueSeparator(String.valueOf(keyValueSeparator));
  }

  /**
   * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
   * this {@code Joiner} otherwise.
   */
  public MapJoiner withKeyValueSeparator(String keyValueSeparator) {
    return new MapJoiner(this, keyValueSeparator);
  }

  /**
   * An object that joins map entries in the same manner as {@code Joiner} joins iterables and
   * arrays. Like {@code Joiner}, it is thread-safe and immutable.
   *
   *
In addition to operating on {@code Map} instances, {@code MapJoiner} can operate on {@code
   * Multimap} entries in two distinct modes:
   *
   *

   *
To output a separate entry for each key-value pair, pass {@code multimap.entries()} to a
   *       {@code MapJoiner} method that accepts entries as input, and receive output of the form
   *       {@code key1=A&key1=B&key2=C}.
   *
To output a single entry for each key, pass {@code multimap.asMap()} to a {@code
   *       MapJoiner} method that accepts a map as input, and receive output of the form {@code
   *       key1=[A, B]&key2=C}.
   *

   *
   * @since 2.0
   */
  public static final class MapJoiner {
    private final Joiner joiner;
    private final String keyValueSeparator;

    private MapJoiner(Joiner joiner, String keyValueSeparator) {
      this.joiner = joiner; // only "this" is ever passed, so don't checkNotNull
      this.keyValueSeparator = checkNotNull(keyValueSeparator);
    }

    /**
     * Appends the string representation of each entry of {@code map}, using the previously
     * configured separator and key-value separator, to {@code appendable}.
     */
    @CanIgnoreReturnValue
    public  A appendTo(A appendable, Map<?, ?> map) throws IOException {
      return appendTo(appendable, map.entrySet());
    }

    /**
     * Appends the string representation of each entry of {@code map}, using the previously
     * configured separator and key-value separator, to {@code builder}. Identical to {@link
     * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}.
     */
    @CanIgnoreReturnValue
    public StringBuilder appendTo(StringBuilder builder, Map<?, ?> map) {
      return appendTo(builder, map.entrySet());
    }

    /**
     * Appends the string representation of each entry in {@code entries}, using the previously
     * configured separator and key-value separator, to {@code appendable}.
     *
     * @since 10.0
     */
    @Beta
    @CanIgnoreReturnValue
    public  A appendTo(A appendable, Iterable<? extends Entry<?, ?>> entries)
        throws IOException {
      return appendTo(appendable, entries.iterator());
    }

    /**
     * Appends the string representation of each entry in {@code entries}, using the previously
     * configured separator and key-value separator, to {@code appendable}.
     *
     * @since 11.0
     */
    @Beta
    @CanIgnoreReturnValue
    public  A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
        throws IOException {
      checkNotNull(appendable);
      if (parts.hasNext()) {
        Entry<?, ?> entry = parts.next();
        appendable.append(joiner.toString(entry.getKey()));
        appendable.append(keyValueSeparator);
        appendable.append(joiner.toString(entry.getValue()));
        while (parts.hasNext()) {
          appendable.append(joiner.separator);
          Entry<?, ?> e = parts.next();
          appendable.append(joiner.toString(e.getKey()));
          appendable.append(keyValueSeparator);
          appendable.append(joiner.toString(e.getValue()));
        }
      }
      return appendable;
    }

    /**
     * Appends the string representation of each entry in {@code entries}, using the previously
     * configured separator and key-value separator, to {@code builder}. Identical to {@link
     * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
     *
     * @since 10.0
     */
    @Beta
    @CanIgnoreReturnValue
    public StringBuilder appendTo(StringBuilder builder, Iterable<? extends Entry<?, ?>> entries) {
      return appendTo(builder, entries.iterator());
    }

    /**
     * Appends the string representation of each entry in {@code entries}, using the previously
     * configured separator and key-value separator, to {@code builder}. Identical to {@link
     * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
     *
     * @since 11.0
     */
    @Beta
    @CanIgnoreReturnValue
    public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) {
      try {
        appendTo((Appendable) builder, entries);
      } catch (IOException impossible) {
        throw new AssertionError(impossible);
      }
      return builder;
    }

    /**
     * Returns a string containing the string representation of each entry of {@code map}, using the
     * previously configured separator and key-value separator.
     */
    public String join(Map<?, ?> map) {
      return join(map.entrySet());
    }

    /**
     * Returns a string containing the string representation of each entry in {@code entries}, using
     * the previously configured separator and key-value separator.
     *
     * @since 10.0
     */
    @Beta
    public String join(Iterable<? extends Entry<?, ?>> entries) {
      return join(entries.iterator());
    }

    /**
     * Returns a string containing the string representation of each entry in {@code entries}, using
     * the previously configured separator and key-value separator.
     *
     * @since 11.0
     */
    @Beta
    public String join(Iterator<? extends Entry<?, ?>> entries) {
      return appendTo(new StringBuilder(), entries).toString();
    }

    /**
     * Returns a map joiner with the same behavior as this one, except automatically substituting
     * {@code nullText} for any provided null keys or values.
     */
    public MapJoiner useForNull(String nullText) {
      return new MapJoiner(joiner.useForNull(nullText), keyValueSeparator);
    }
  }

  CharSequence toString(Object part) {
    checkNotNull(part); // checkNotNull for GWT (do not optimize).
    return (part instanceof CharSequence) ? (CharSequence) part : part.toString();
  }

  private static Iterable<Object> iterable(
      final Object first, final Object second, final Object[] rest) {
    checkNotNull(rest);
    return new AbstractList<Object>() {
      @Override
      public int size() {
        return rest.length + 2;
      }

      @Override
      public Object get(int index) {
        switch (index) {
          case 0:
            return first;
          case 1:
            return second;
          default:
            return rest[index - 2];
        }
      }
    };
  }
}


/*
 * Copyright (C) 2017 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.checkNotNull;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Preconditions;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.errorprone.annotations.Immutable;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.RandomAccess;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * An immutable array of {@code int} values, with an API resembling {@link List}.
 *
 *
Advantages compared to {@code int[]}:
 *
 *

 *
All the many well-known advantages of immutability (read Effective Java, third
 *       edition, Item 17).
 *
Has the value-based (not identity-based) {@link #equals}, {@link #hashCode}, and {@link
 *       #toString} behavior you expect.
 *
Offers useful operations beyond just {@code get} and {@code length}, so you don't have to
 *       hunt through classes like {@link Arrays} and {@link Ints} for them.
 *
Supports a copy-free {@link #subArray} view, so methods that accept this type don't need to
 *       add overloads that accept start and end indexes.
 *
Can be streamed without "breaking the chain": {@code foo.getBarInts().stream()...}.
 *
Access to all collection-based utilities via {@link #asList} (though at the cost of
 *       allocating garbage).
 *

 *
 *
Disadvantages compared to {@code int[]}:
 *
 *

 *
Memory footprint has a fixed overhead (about 24 bytes per instance).
 *
Some construction use cases force the data to be copied (though several construction
 *       APIs are offered that don't).
 *
Can't be passed directly to methods that expect {@code int[]} (though the most common
 *       utilities do have replacements here).
 *
Dependency on {@code com.google.common} / Guava.
 *

 *
 *
Advantages compared to {@link com.google.common.collect.ImmutableList ImmutableList}{@code
 * <Integer>}:
 *
 *

 *
Improved memory compactness and locality.
 *
Can be queried without allocating garbage.
 *
Access to {@code IntStream} features (like {@link IntStream#sum}) using {@code stream()}
 *       instead of the awkward {@code stream().mapToInt(v -> v)}.
 *

 *
 *
Disadvantages compared to {@code ImmutableList<Integer>}:
 *
 *

 *
Can't be passed directly to methods that expect {@code Iterable}, {@code Collection}, or
 *       {@code List} (though the most common utilities do have replacements here, and there is a
 *       lazy {@link #asList} view).
 *

 *
 * @since 22.0
 */
@Beta
@GwtCompatible
@Immutable
public final class ImmutableIntArray implements Serializable {
  private static final ImmutableIntArray EMPTY = new ImmutableIntArray(new int[0]);

  /** Returns the empty array. */
  public static ImmutableIntArray of() {
    return EMPTY;
  }

  /** Returns an immutable array containing a single value. */
  public static ImmutableIntArray of(int e0) {
    return new ImmutableIntArray(new int[] {e0});
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray of(int e0, int e1) {
    return new ImmutableIntArray(new int[] {e0, e1});
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray of(int e0, int e1, int e2) {
    return new ImmutableIntArray(new int[] {e0, e1, e2});
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray of(int e0, int e1, int e2, int e3) {
    return new ImmutableIntArray(new int[] {e0, e1, e2, e3});
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray of(int e0, int e1, int e2, int e3, int e4) {
    return new ImmutableIntArray(new int[] {e0, e1, e2, e3, e4});
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray of(int e0, int e1, int e2, int e3, int e4, int e5) {
    return new ImmutableIntArray(new int[] {e0, e1, e2, e3, e4, e5});
  }

  // TODO(kevinb): go up to 11?

  /**
   * Returns an immutable array containing the given values, in order.
   *
   *
The array {@code rest} must not be longer than {@code Integer.MAX_VALUE - 1}.
   */
  // Use (first, rest) so that `of(someIntArray)` won't compile (they should use copyOf), which is
  // okay since we have to copy the just-created array anyway.
  public static ImmutableIntArray of(int first, int... rest) {
    checkArgument(
        rest.length <= Integer.MAX_VALUE - 1, "the total number of elements must fit in an int");
    int[] array = new int[rest.length + 1];
    array[0] = first;
    System.arraycopy(rest, 0, array, 1, rest.length);
    return new ImmutableIntArray(array);
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray copyOf(int[] values) {
    return values.length == 0 ? EMPTY : new ImmutableIntArray(Arrays.copyOf(values, values.length));
  }

  /** Returns an immutable array containing the given values, in order. */
  public static ImmutableIntArray copyOf(Collection<Integer> values) {
    return values.isEmpty() ? EMPTY : new ImmutableIntArray(Ints.toArray(values));
  }

  /**
   * Returns an immutable array containing the given values, in order.
   *
   *
Performance note: this method delegates to {@link #copyOf(Collection)} if {@code
   * values} is a {@link Collection}. Otherwise it creates a {@link #builder} and uses {@link
   * Builder#addAll(Iterable)}, with all the performance implications associated with that.
   */
  public static ImmutableIntArray copyOf(Iterable<Integer> values) {
    if (values instanceof Collection) {
      return copyOf((Collection<Integer>) values);
    }
    return builder().addAll(values).build();
  }

  /** Returns an immutable array containing all the values from {@code stream}, in order. */
  public static ImmutableIntArray copyOf(IntStream stream) {
    // Note this uses very different growth behavior from copyOf(Iterable) and the builder.
    int[] array = stream.toArray();
    return (array.length == 0) ? EMPTY : new ImmutableIntArray(array);
  }

  /**
   * Returns a new, empty builder for {@link ImmutableIntArray} instances, sized to hold up to
   * {@code initialCapacity} values without resizing. The returned builder is not thread-safe.
   *
   *
Performance note: When feasible, {@code initialCapacity} should be the exact number
   * of values that will be added, if that knowledge is readily available. It is better to guess a
   * value slightly too high than slightly too low. If the value is not exact, the {@link
   * ImmutableIntArray} that is built will very likely occupy more memory than strictly necessary;
   * to trim memory usage, build using {@code builder.build().trimmed()}.
   */
  public static Builder builder(int initialCapacity) {
    checkArgument(initialCapacity >= 0, "Invalid initialCapacity: %s", initialCapacity);
    return new Builder(initialCapacity);
  }

  /**
   * Returns a new, empty builder for {@link ImmutableIntArray} instances, with a default initial
   * capacity. The returned builder is not thread-safe.
   *
   *
Performance note: The {@link ImmutableIntArray} that is built will very likely occupy
   * more memory than necessary; to trim memory usage, build using {@code
   * builder.build().trimmed()}.
   */
  public static Builder builder() {
    return new Builder(10);
  }

  /**
   * A builder for {@link ImmutableIntArray} instances; obtained using {@link
   * ImmutableIntArray#builder}.
   */
  @CanIgnoreReturnValue
  public static final class Builder {
    private int[] array;
    private int count = 0; // <= array.length

    Builder(int initialCapacity) {
      array = new int[initialCapacity];
    }

    /**
     * Appends {@code value} to the end of the values the built {@link ImmutableIntArray} will
     * contain.
     */
    public Builder add(int value) {
      ensureRoomFor(1);
      array[count] = value;
      count += 1;
      return this;
    }

    /**
     * Appends {@code values}, in order, to the end of the values the built {@link
     * ImmutableIntArray} will contain.
     */
    public Builder addAll(int[] values) {
      ensureRoomFor(values.length);
      System.arraycopy(values, 0, array, count, values.length);
      count += values.length;
      return this;
    }

    /**
     * Appends {@code values}, in order, to the end of the values the built {@link
     * ImmutableIntArray} will contain.
     */
    public Builder addAll(Iterable<Integer> values) {
      if (values instanceof Collection) {
        return addAll((Collection<Integer>) values);
      }
      for (Integer value : values) {
        add(value);
      }
      return this;
    }

    /**
     * Appends {@code values}, in order, to the end of the values the built {@link
     * ImmutableIntArray} will contain.
     */
    public Builder addAll(Collection<Integer> values) {
      ensureRoomFor(values.size());
      for (Integer value : values) {
        array[count++] = value;
      }
      return this;
    }

    /**
     * Appends all values from {@code stream}, in order, to the end of the values the built {@link
     * ImmutableIntArray} will contain.
     */
    public Builder addAll(IntStream stream) {
      Spliterator.OfInt spliterator = stream.spliterator();
      long size = spliterator.getExactSizeIfKnown();
      if (size > 0) { // known *and* nonempty
        ensureRoomFor(Ints.saturatedCast(size));
      }
      spliterator.forEachRemaining((IntConsumer) this::add);
      return this;
    }

    /**
     * Appends {@code values}, in order, to the end of the values the built {@link
     * ImmutableIntArray} will contain.
     */
    public Builder addAll(ImmutableIntArray values) {
      ensureRoomFor(values.length());
      System.arraycopy(values.array, values.start, array, count, values.length());
      count += values.length();
      return this;
    }

    private void ensureRoomFor(int numberToAdd) {
      int newCount = count + numberToAdd; // TODO(kevinb): check overflow now?
      if (newCount > array.length) {
        int[] newArray = new int[expandedCapacity(array.length, newCount)];
        System.arraycopy(array, 0, newArray, 0, count);
        this.array = newArray;
      }
    }

    // Unfortunately this is pasted from ImmutableCollection.Builder.
    private 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;
    }

    /**
     * Returns a new immutable array. The builder can continue to be used after this call, to append
     * more values and build again.
     *
     *
Performance note: the returned array is backed by the same array as the builder, so
     * no data is copied as part of this step, but this may occupy more memory than strictly
     * necessary. To copy the data to a right-sized backing array, use {@code .build().trimmed()}.
     */
    @CheckReturnValue
    public ImmutableIntArray build() {
      return count == 0 ? EMPTY : new ImmutableIntArray(array, 0, count);
    }
  }

  // Instance stuff here

  // The array is never mutated after storing in this field and the construction strategies ensure
  // it doesn't escape this class
  @SuppressWarnings("Immutable")
  private final int[] array;

  /*
   * TODO(kevinb): evaluate the trade-offs of going bimorphic to save these two fields from most
   * instances. Note that the instances that would get smaller are the right set to care about
   * optimizing, because the rest have the option of calling `trimmed`.
   */

  private final transient int start; // it happens that we only serialize instances where this is 0
  private final int end; // exclusive

  private ImmutableIntArray(int[] array) {
    this(array, 0, array.length);
  }

  private ImmutableIntArray(int[] array, int start, int end) {
    this.array = array;
    this.start = start;
    this.end = end;
  }

  /** Returns the number of values in this array. */
  public int length() {
    return end - start;
  }

  /** Returns {@code true} if there are no values in this array ({@link #length} is zero). */
  public boolean isEmpty() {
    return end == start;
  }

  /**
   * Returns the {@code int} value present at the given index.
   *
   * @throws IndexOutOfBoundsException if {@code index} is negative, or greater than or equal to
   *     {@link #length}
   */
  public int get(int index) {
    Preconditions.checkElementIndex(index, length());
    return array[start + index];
  }

  /**
   * Returns the smallest index for which {@link #get} returns {@code target}, or {@code -1} if no
   * such index exists. Equivalent to {@code asList().indexOf(target)}.
   */
  public int indexOf(int target) {
    for (int i = start; i < end; i++) {
      if (array[i] == target) {
        return i - start;
      }
    }
    return -1;
  }

  /**
   * Returns the largest index for which {@link #get} returns {@code target}, or {@code -1} if no
   * such index exists. Equivalent to {@code asList().lastIndexOf(target)}.
   */
  public int lastIndexOf(int target) {
    for (int i = end - 1; i >= start; i--) {
      if (array[i] == target) {
        return i - start;
      }
    }
    return -1;
  }

  /**
   * Returns {@code true} if {@code target} is present at any index in this array. Equivalent to
   * {@code asList().contains(target)}.
   */
  public boolean contains(int target) {
    return indexOf(target) >= 0;
  }

  /** Invokes {@code consumer} for each value contained in this array, in order. */
  public void forEach(IntConsumer consumer) {
    checkNotNull(consumer);
    for (int i = start; i < end; i++) {
      consumer.accept(array[i]);
    }
  }

  /** Returns a stream over the values in this array, in order. */
  public IntStream stream() {
    return Arrays.stream(array, start, end);
  }

  /** Returns a new, mutable copy of this array's values, as a primitive {@code int[]}. */
  public int[] toArray() {
    return Arrays.copyOfRange(array, start, end);
  }

  /**
   * Returns a new immutable array containing the values in the specified range.
   *
   *
Performance note: The returned array has the same full memory footprint as this one
   * does (no actual copying is performed). To reduce memory usage, use {@code subArray(start,
   * end).trimmed()}.
   */
  public ImmutableIntArray subArray(int startIndex, int endIndex) {
    Preconditions.checkPositionIndexes(startIndex, endIndex, length());
    return startIndex == endIndex
        ? EMPTY
        : new ImmutableIntArray(array, start + startIndex, start + endIndex);
  }

  private Spliterator.OfInt spliterator() {
    return Spliterators.spliterator(array, start, end, Spliterator.IMMUTABLE | Spliterator.ORDERED);
  }

  /**
   * Returns an immutable view of this array's values as a {@code List}; note that {@code
   * int} values are boxed into {@link Integer} instances on demand, which can be very expensive.
   * The returned list should be used once and discarded. For any usages beyond that, pass the
   * returned list to {@link com.google.common.collect.ImmutableList#copyOf(Collection)
   * ImmutableList.copyOf} and use that list instead.
   */
  public List<Integer> asList() {
    /*
     * Typically we cache this kind of thing, but much repeated use of this view is a performance
     * anti-pattern anyway. If we cache, then everyone pays a price in memory footprint even if
     * they never use this method.
     */
    return new AsList(this);
  }

  static class AsList extends AbstractList<Integer> implements RandomAccess, Serializable {
    private final ImmutableIntArray parent;

    private AsList(ImmutableIntArray parent) {
      this.parent = parent;
    }

    // inherit: isEmpty, containsAll, toArray x2, iterator, listIterator, stream, forEach, mutations

    @Override
    public int size() {
      return parent.length();
    }

    @Override
    public Integer get(int index) {
      return parent.get(index);
    }

    @Override
    public boolean contains(Object target) {
      return indexOf(target) >= 0;
    }

    @Override
    public int indexOf(Object target) {
      return target instanceof Integer ? parent.indexOf((Integer) target) : -1;
    }

    @Override
    public int lastIndexOf(Object target) {
      return target instanceof Integer ? parent.lastIndexOf((Integer) target) : -1;
    }

    @Override
    public List<Integer> subList(int fromIndex, int toIndex) {
      return parent.subArray(fromIndex, toIndex).asList();
    }

    // The default List spliterator is not efficiently splittable
    @Override
    public Spliterator<Integer> spliterator() {
      return parent.spliterator();
    }

    @Override
    public boolean equals(@Nullable Object object) {
      if (object instanceof AsList) {
        AsList that = (AsList) object;
        return this.parent.equals(that.parent);
      }
      // We could delegate to super now but it would still box too much
      if (!(object instanceof List)) {
        return false;
      }
      List<?> that = (List<?>) object;
      if (this.size() != that.size()) {
        return false;
      }
      int i = parent.start;
      // Since `that` is very likely RandomAccess we could avoid allocating this iterator...
      for (Object element : that) {
        if (!(element instanceof Integer) || parent.array[i++] != (Integer) element) {
          return false;
        }
      }
      return true;
    }

    // Because we happen to use the same formula. If that changes, just don't override this.
    @Override
    public int hashCode() {
      return parent.hashCode();
    }

    @Override
    public String toString() {
      return parent.toString();
    }
  }

  /**
   * Returns {@code true} if {@code object} is an {@code ImmutableIntArray} containing the same
   * values as this one, in the same order.
   */
  @Override
  public boolean equals(@Nullable Object object) {
    if (object == this) {
      return true;
    }
    if (!(object instanceof ImmutableIntArray)) {
      return false;
    }
    ImmutableIntArray that = (ImmutableIntArray) object;
    if (this.length() != that.length()) {
      return false;
    }
    for (int i = 0; i < length(); i++) {
      if (this.get(i) != that.get(i)) {
        return false;
      }
    }
    return true;
  }

  /** Returns an unspecified hash code for the contents of this immutable array. */
  @Override
  public int hashCode() {
    int hash = 1;
    for (int i = start; i < end; i++) {
      hash *= 31;
      hash += Ints.hashCode(array[i]);
    }
    return hash;
  }

  /**
   * Returns a string representation of this array in the same form as {@link
   * Arrays#toString(int[])}, for example {@code "[1, 2, 3]"}.
   */
  @Override
  public String toString() {
    if (isEmpty()) {
      return "[]";
    }
    StringBuilder builder = new StringBuilder(length() * 5); // rough estimate is fine
    builder.append('[').append(array[start]);

    for (int i = start + 1; i < end; i++) {
      builder.append(", ").append(array[i]);
    }
    builder.append(']');
    return builder.toString();
  }

  /**
   * Returns an immutable array containing the same values as {@code this} array. This is logically
   * a no-op, and in some circumstances {@code this} itself is returned. However, if this instance
   * is a {@link #subArray} view of a larger array, this method will copy only the appropriate range
   * of values, resulting in an equivalent array with a smaller memory footprint.
   */
  public ImmutableIntArray trimmed() {
    return isPartialView() ? new ImmutableIntArray(toArray()) : this;
  }

  private boolean isPartialView() {
    return start > 0 || end < array.length;
  }

  Object writeReplace() {
    return trimmed();
  }

  Object readResolve() {
    return isEmpty() ? EMPTY : this;
  }
}


/*
 * 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.math;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.DoubleUtils.IMPLICIT_BIT;
import static com.google.common.math.DoubleUtils.SIGNIFICAND_BITS;
import static com.google.common.math.DoubleUtils.getSignificand;
import static com.google.common.math.DoubleUtils.isFinite;
import static com.google.common.math.DoubleUtils.isNormal;
import static com.google.common.math.DoubleUtils.scaleNormalize;
import static com.google.common.math.MathPreconditions.checkInRangeForRoundingInputs;
import static com.google.common.math.MathPreconditions.checkNonNegative;
import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
import static java.lang.Math.abs;
import static java.lang.Math.copySign;
import static java.lang.Math.getExponent;
import static java.lang.Math.log;
import static java.lang.Math.rint;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.primitives.Booleans;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.Iterator;

/**
 * A class for arithmetic on doubles that is not covered by {@link java.lang.Math}.
 *
 * @author Louis Wasserman
 * @since 11.0
 */
@GwtCompatible(emulated = true)
public final class DoubleMath {
  /*
   * This method returns a value y such that rounding y DOWN (towards zero) gives the same result as
   * rounding x according to the specified mode.
   */
  @GwtIncompatible // #isMathematicalInteger, com.google.common.math.DoubleUtils
  static double roundIntermediate(double x, RoundingMode mode) {
    if (!isFinite(x)) {
      throw new ArithmeticException("input is infinite or NaN");
    }
    switch (mode) {
      case UNNECESSARY:
        checkRoundingUnnecessary(isMathematicalInteger(x));
        return x;

      case FLOOR:
        if (x >= 0.0 || isMathematicalInteger(x)) {
          return x;
        } else {
          return (long) x - 1;
        }

      case CEILING:
        if (x <= 0.0 || isMathematicalInteger(x)) {
          return x;
        } else {
          return (long) x + 1;
        }

      case DOWN:
        return x;

      case UP:
        if (isMathematicalInteger(x)) {
          return x;
        } else {
          return (long) x + (x > 0 ? 1 : -1);
        }

      case HALF_EVEN:
        return rint(x);

      case HALF_UP:
        {
          double z = rint(x);
          if (abs(x - z) == 0.5) {
            return x + copySign(0.5, x);
          } else {
            return z;
          }
        }

      case HALF_DOWN:
        {
          double z = rint(x);
          if (abs(x - z) == 0.5) {
            return x;
          } else {
            return z;
          }
        }

      default:
        throw new AssertionError();
    }
  }

  /**
   * Returns the {@code int} value that is equal to {@code x} rounded with the specified rounding
   * mode, if possible.
   *
   * @throws ArithmeticException if
   *

   *
{@code x} is infinite or NaN
   *
{@code x}, after being rounded to a mathematical integer using the specified rounding
   *           mode, is either less than {@code Integer.MIN_VALUE} or greater than {@code
   *           Integer.MAX_VALUE}
   *
{@code x} is not a mathematical integer and {@code mode} is {@link
   *           RoundingMode#UNNECESSARY}
   *

   */
  @GwtIncompatible // #roundIntermediate
  public static int roundToInt(double x, RoundingMode mode) {
    double z = roundIntermediate(x, mode);
    checkInRangeForRoundingInputs(
        z > MIN_INT_AS_DOUBLE - 1.0 & z < MAX_INT_AS_DOUBLE + 1.0, x, mode);
    return (int) z;
  }

  private static final double MIN_INT_AS_DOUBLE = -0x1p31;
  private static final double MAX_INT_AS_DOUBLE = 0x1p31 - 1.0;

  /**
   * Returns the {@code long} value that is equal to {@code x} rounded with the specified rounding
   * mode, if possible.
   *
   * @throws ArithmeticException if
   *

   *
{@code x} is infinite or NaN
   *
{@code x}, after being rounded to a mathematical integer using the specified rounding
   *           mode, is either less than {@code Long.MIN_VALUE} or greater than {@code
   *           Long.MAX_VALUE}
   *
{@code x} is not a mathematical integer and {@code mode} is {@link
   *           RoundingMode#UNNECESSARY}
   *

   */
  @GwtIncompatible // #roundIntermediate
  public static long roundToLong(double x, RoundingMode mode) {
    double z = roundIntermediate(x, mode);
    checkInRangeForRoundingInputs(
        MIN_LONG_AS_DOUBLE - z < 1.0 & z < MAX_LONG_AS_DOUBLE_PLUS_ONE, x, mode);
    return (long) z;
  }

  private static final double MIN_LONG_AS_DOUBLE = -0x1p63;
  /*
   * We cannot store Long.MAX_VALUE as a double without losing precision. Instead, we store
   * Long.MAX_VALUE + 1 == -Long.MIN_VALUE, and then offset all comparisons by 1.
   */
  private static final double MAX_LONG_AS_DOUBLE_PLUS_ONE = 0x1p63;

  /**
   * Returns the {@code BigInteger} value that is equal to {@code x} rounded with the specified
   * rounding mode, if possible.
   *
   * @throws ArithmeticException if
   *

   *
{@code x} is infinite or NaN
   *
{@code x} is not a mathematical integer and {@code mode} is {@link
   *           RoundingMode#UNNECESSARY}
   *

   */
  // #roundIntermediate, java.lang.Math.getExponent, com.google.common.math.DoubleUtils
  @GwtIncompatible
  public static BigInteger roundToBigInteger(double x, RoundingMode mode) {
    x = roundIntermediate(x, mode);
    if (MIN_LONG_AS_DOUBLE - x < 1.0 & x < MAX_LONG_AS_DOUBLE_PLUS_ONE) {
      return BigInteger.valueOf((long) x);
    }
    int exponent = getExponent(x);
    long significand = getSignificand(x);
    BigInteger result = BigInteger.valueOf(significand).shiftLeft(exponent - SIGNIFICAND_BITS);
    return (x < 0) ? result.negate() : result;
  }

  /**
   * Returns {@code true} if {@code x} is exactly equal to {@code 2^k} for some finite integer
   * {@code k}.
   */
  @GwtIncompatible // com.google.common.math.DoubleUtils
  public static boolean isPowerOfTwo(double x) {
    if (x > 0.0 && isFinite(x)) {
      long significand = getSignificand(x);
      return (significand & (significand - 1)) == 0;
    }
    return false;
  }

  /**
   * Returns the base 2 logarithm of a double value.
   *
   *
Special cases:
   *
   *

   *
If {@code x} is NaN or less than zero, the result is NaN.
   *
If {@code x} is positive infinity, the result is positive infinity.
   *
If {@code x} is positive or negative zero, the result is negative infinity.
   *

   *
   *
The computed result is within 1 ulp of the exact result.
   *
   *
If the result of this method will be immediately rounded to an {@code int}, {@link
   * #log2(double, RoundingMode)} is faster.
   */
  public static double log2(double x) {
    return log(x) / LN_2; // surprisingly within 1 ulp according to tests
  }

  /**
   * Returns the base 2 logarithm of a double value, rounded with the specified rounding mode to an
   * {@code int}.
   *
   *
Regardless of the rounding mode, this is faster than {@code (int) log2(x)}.
   *
   * @throws IllegalArgumentException if {@code x <= 0.0}, {@code x} is NaN, or {@code x} is
   *     infinite
   */
  @GwtIncompatible // java.lang.Math.getExponent, com.google.common.math.DoubleUtils
  @SuppressWarnings("fallthrough")
  public static int log2(double x, RoundingMode mode) {
    checkArgument(x > 0.0 && isFinite(x), "x must be positive and finite");
    int exponent = getExponent(x);
    if (!isNormal(x)) {
      return log2(x * IMPLICIT_BIT, mode) - SIGNIFICAND_BITS;
      // Do the calculation on a normal value.
    }
    // x is positive, finite, and normal
    boolean increment;
    switch (mode) {
      case UNNECESSARY:
        checkRoundingUnnecessary(isPowerOfTwo(x));
        // fall through
      case FLOOR:
        increment = false;
        break;
      case CEILING:
        increment = !isPowerOfTwo(x);
        break;
      case DOWN:
        increment = exponent < 0 & !isPowerOfTwo(x);
        break;
      case UP:
        increment = exponent >= 0 & !isPowerOfTwo(x);
        break;
      case HALF_DOWN:
      case HALF_EVEN:
      case HALF_UP:
        double xScaled = scaleNormalize(x);
        // sqrt(2) is irrational, and the spec is relative to the "exact numerical result,"
        // so log2(x) is never exactly exponent + 0.5.
        increment = (xScaled * xScaled) > 2.0;
        break;
      default:
        throw new AssertionError();
    }
    return increment ? exponent + 1 : exponent;
  }

  private static final double LN_2 = log(2);

  /**
   * Returns {@code true} if {@code x} represents a mathematical integer.
   *
   *
This is equivalent to, but not necessarily implemented as, the expression {@code
   * !Double.isNaN(x) && !Double.isInfinite(x) && x == Math.rint(x)}.
   */
  @GwtIncompatible // java.lang.Math.getExponent, com.google.common.math.DoubleUtils
  public static boolean isMathematicalInteger(double x) {
    return isFinite(x)
        && (x == 0.0
            || SIGNIFICAND_BITS - Long.numberOfTrailingZeros(getSignificand(x)) <= getExponent(x));
  }

  /**
   * Returns {@code n!}, that is, the product of the first {@code n} positive integers, {@code 1} if
   * {@code n == 0}, or {@code n!}, or {@link Double#POSITIVE_INFINITY} if {@code n! >
   * Double.MAX_VALUE}.
   *
   *
The result is within 1 ulp of the true value.
   *
   * @throws IllegalArgumentException if {@code n < 0}
   */
  public static double factorial(int n) {
    checkNonNegative("n", n);
    if (n > MAX_FACTORIAL) {
      return Double.POSITIVE_INFINITY;
    } else {
      // Multiplying the last (n & 0xf) values into their own accumulator gives a more accurate
      // result than multiplying by everySixteenthFactorial[n >> 4] directly.
      double accum = 1.0;
      for (int i = 1 + (n & ~0xf); i <= n; i++) {
        accum *= i;
      }
      return accum * everySixteenthFactorial[n >> 4];
    }
  }

  @VisibleForTesting static final int MAX_FACTORIAL = 170;

  @VisibleForTesting
  static final double[] everySixteenthFactorial = {
    0x1.0p0,
    0x1.30777758p44,
    0x1.956ad0aae33a4p117,
    0x1.ee69a78d72cb6p202,
    0x1.fe478ee34844ap295,
    0x1.c619094edabffp394,
    0x1.3638dd7bd6347p498,
    0x1.7cac197cfe503p605,
    0x1.1e5dfc140e1e5p716,
    0x1.8ce85fadb707ep829,
    0x1.95d5f3d928edep945
  };

  /**
   * Returns {@code true} if {@code a} and {@code b} are within {@code tolerance} of each other.
   *
   *
Technically speaking, this is equivalent to {@code Math.abs(a - b) <= tolerance ||
   * Double.valueOf(a).equals(Double.valueOf(b))}.
   *
   *
Notable special cases include:
   *
   *

   *
All NaNs are fuzzily equal.
   *
If {@code a == b}, then {@code a} and {@code b} are always fuzzily equal.
   *
Positive and negative zero are always fuzzily equal.
   *
If {@code tolerance} is zero, and neither {@code a} nor {@code b} is NaN, then {@code a}
   *       and {@code b} are fuzzily equal if and only if {@code a == b}.
   *
With {@link Double#POSITIVE_INFINITY} tolerance, all non-NaN values are fuzzily equal.
   *
With finite tolerance, {@code Double.POSITIVE_INFINITY} and {@code
   *       Double.NEGATIVE_INFINITY} are fuzzily equal only to themselves.
   *

   *
   *
This is reflexive and symmetric, but not transitive, so it is not an
   * equivalence relation and not suitable for use in {@link Object#equals}
   * implementations.
   *
   * @throws IllegalArgumentException if {@code tolerance} is {@code < 0} or NaN
   * @since 13.0
   */
  public static boolean fuzzyEquals(double a, double b, double tolerance) {
    MathPreconditions.checkNonNegative("tolerance", tolerance);
    return Math.copySign(a - b, 1.0) <= tolerance
        // copySign(x, 1.0) is a branch-free version of abs(x), but with different NaN semantics
        || (a == b) // needed to ensure that infinities equal themselves
        || (Double.isNaN(a) && Double.isNaN(b));
  }

  /**
   * Compares {@code a} and {@code b} "fuzzily," with a tolerance for nearly-equal values.
   *
   *
This method is equivalent to {@code fuzzyEquals(a, b, tolerance) ? 0 : Double.compare(a,
   * b)}. In particular, like {@link Double#compare(double, double)}, it treats all NaN values as
   * equal and greater than all other values (including {@link Double#POSITIVE_INFINITY}).
   *
   *
This is not a total ordering and is not suitable for use in {@link
   * Comparable#compareTo} implementations. In particular, it is not transitive.
   *
   * @throws IllegalArgumentException if {@code tolerance} is {@code < 0} or NaN
   * @since 13.0
   */
  public static int fuzzyCompare(double a, double b, double tolerance) {
    if (fuzzyEquals(a, b, tolerance)) {
      return 0;
    } else if (a  b) {
      return 1;
    } else {
      return Booleans.compare(Double.isNaN(a), Double.isNaN(b));
    }
  }

  /**
   * Returns the arithmetic mean of
   * {@code values}.
   *
   *
If these values are a sample drawn from a population, this is also an unbiased estimator of
   * the arithmetic mean of the population.
   *
   * @param values a nonempty series of values
   * @throws IllegalArgumentException if {@code values} is empty or contains any non-finite value
   * @deprecated Use {@link Stats#meanOf} instead, noting the less strict handling of non-finite
   *     values.
   */
  @Deprecated
  // com.google.common.math.DoubleUtils
  @GwtIncompatible
  public static double mean(double... values) {
    checkArgument(values.length > 0, "Cannot take mean of 0 values");
    long count = 1;
    double mean = checkFinite(values[0]);
    for (int index = 1; index < values.length; ++index) {
      checkFinite(values[index]);
      count++;
      // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
      mean += (values[index] - mean) / count;
    }
    return mean;
  }

  /**
   * Returns the arithmetic mean of
   * {@code values}.
   *
   *
If these values are a sample drawn from a population, this is also an unbiased estimator of
   * the arithmetic mean of the population.
   *
   * @param values a nonempty series of values
   * @throws IllegalArgumentException if {@code values} is empty
   * @deprecated Use {@link Stats#meanOf} instead, noting the less strict handling of non-finite
   *     values.
   */
  @Deprecated
  public static double mean(int... values) {
    checkArgument(values.length > 0, "Cannot take mean of 0 values");
    // The upper bound on the the length of an array and the bounds on the int values mean that, in
    // this case only, we can compute the sum as a long without risking overflow or loss of
    // precision. So we do that, as it's slightly quicker than the Knuth algorithm.
    long sum = 0;
    for (int index = 0; index < values.length; ++index) {
      sum += values[index];
    }
    return (double) sum / values.length;
  }

  /**
   * Returns the arithmetic mean of
   * {@code values}.
   *
   *
If these values are a sample drawn from a population, this is also an unbiased estimator of
   * the arithmetic mean of the population.
   *
   * @param values a nonempty series of values, which will be converted to {@code double} values
   *     (this may cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15))
   * @throws IllegalArgumentException if {@code values} is empty
   * @deprecated Use {@link Stats#meanOf} instead, noting the less strict handling of non-finite
   *     values.
   */
  @Deprecated
  public static double mean(long... values) {
    checkArgument(values.length > 0, "Cannot take mean of 0 values");
    long count = 1;
    double mean = values[0];
    for (int index = 1; index < values.length; ++index) {
      count++;
      // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
      mean += (values[index] - mean) / count;
    }
    return mean;
  }

  /**
   * Returns the arithmetic mean of
   * {@code values}.
   *
   *
If these values are a sample drawn from a population, this is also an unbiased estimator of
   * the arithmetic mean of the population.
   *
   * @param values a nonempty series of values, which will be converted to {@code double} values
   *     (this may cause loss of precision)
   * @throws IllegalArgumentException if {@code values} is empty or contains any non-finite value
   * @deprecated Use {@link Stats#meanOf} instead, noting the less strict handling of non-finite
   *     values.
   */
  @Deprecated
  // com.google.common.math.DoubleUtils
  @GwtIncompatible
  public static double mean(Iterable<? extends Number> values) {
    return mean(values.iterator());
  }

  /**
   * Returns the arithmetic mean of
   * {@code values}.
   *
   *
If these values are a sample drawn from a population, this is also an unbiased estimator of
   * the arithmetic mean of the population.
   *
   * @param values a nonempty series of values, which will be converted to {@code double} values
   *     (this may cause loss of precision)
   * @throws IllegalArgumentException if {@code values} is empty or contains any non-finite value
   * @deprecated Use {@link Stats#meanOf} instead, noting the less strict handling of non-finite
   *     values.
   */
  @Deprecated
  // com.google.common.math.DoubleUtils
  @GwtIncompatible
  public static double mean(Iterator<? extends Number> values) {
    checkArgument(values.hasNext(), "Cannot take mean of 0 values");
    long count = 1;
    double mean = checkFinite(values.next().doubleValue());
    while (values.hasNext()) {
      double value = checkFinite(values.next().doubleValue());
      count++;
      // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
      mean += (value - mean) / count;
    }
    return mean;
  }

  @GwtIncompatible // com.google.common.math.DoubleUtils
  @CanIgnoreReturnValue
  private static double checkFinite(double argument) {
    checkArgument(isFinite(argument));
    return argument;
  }

  private DoubleMath() {}
}


/*
 * 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 static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkPositionIndex;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.CollectPreconditions.checkRemove;
import static java.util.Collections.unmodifiableList;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.j2objc.annotations.WeakOuter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractSequentialList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Consumer;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * An implementation of {@code ListMultimap} that supports deterministic iteration order for both
 * keys and values. The iteration order is preserved across non-distinct key values. For example,
 * for the following multimap definition:
 *
 *
{@code
 * Multimap<K, V> multimap = LinkedListMultimap.create();
 * multimap.put(key1, foo);
 * multimap.put(key2, bar);
 * multimap.put(key1, baz);
 * }

 *
 * ... the iteration order for {@link #keys()} is {@code [key1, key2, key1]}, and similarly for
 * {@link #entries()}. Unlike {@link LinkedHashMultimap}, the iteration order is kept consistent
 * between keys, entries and values. For example, calling:
 *
 *
{@code
 * multimap.remove(key1, foo);
 * }

 *
 *
changes the entries iteration order to {@code [key2=bar, key1=baz]} and the key iteration
 * order to {@code [key2, key1]}. The {@link #entries()} iterator returns mutable map entries, and
 * {@link #replaceValues} attempts to preserve iteration order as much as possible.
 *
 *
The collections returned by {@link #keySet()} and {@link #asMap} iterate through the keys in
 * the order they were first added to the multimap. Similarly, {@link #get}, {@link #removeAll}, and
 * {@link #replaceValues} return collections that iterate through the values in the order they were
 * added. The collections generated by {@link #entries()}, {@link #keys()}, and {@link #values}
 * iterate across the key-value mappings in the order they were added to the multimap.
 *
 *
The {@link #values()} and {@link #entries()} methods both return a {@code List}, instead of
 * the {@code Collection} specified by the {@link ListMultimap} interface.
 *
 *
The methods {@link #get}, {@link #keySet()}, {@link #keys()}, {@link #values}, {@link
 * #entries()}, and {@link #asMap} return collections that are views of the multimap. If the
 * multimap is modified while an iteration over any of those collections is in progress, except
 * through the iterator's methods, the results of the iteration are undefined.
 *
 *
Keys and values may be null. All optional multimap methods are supported, and all returned
 * views are modifiable.
 *
 *
This class is not threadsafe when any concurrent operations update the multimap. Concurrent
 * read operations will work correctly. To allow concurrent update operations, wrap your multimap
 * with a call to {@link Multimaps#synchronizedListMultimap}.
 *
 *
See the Guava User Guide article on  {@code
 * Multimap}.
 *
 * @author Mike Bostock
 * @since 2.0
 */
@GwtCompatible(serializable = true, emulated = true)
public class LinkedListMultimap<K, V> extends AbstractMultimap<K, V>
    implements ListMultimap<K, V>, Serializable {
  /*
   * Order is maintained using a linked list containing all key-value pairs. In
   * addition, a series of disjoint linked lists of "siblings", each containing
   * the values for a specific key, is used to implement {@link
   * ValueForKeyIterator} in constant time.
   */

  private static final class Node<K, V> extends AbstractMapEntry<K, V> {
    final @Nullable K key;
    @Nullable V value;
    @Nullable Node<K, V> next; // the next node (with any key)
    @Nullable Node<K, V> previous; // the previous node (with any key)
    @Nullable Node<K, V> nextSibling; // the next node with the same key
    @Nullable Node<K, V> previousSibling; // the previous node with the same key

    Node(@Nullable K key, @Nullable V value) {
      this.key = key;
      this.value = value;
    }

    @Override
    public K getKey() {
      return key;
    }

    @Override
    public V getValue() {
      return value;
    }

    @Override
    public V setValue(@Nullable V newValue) {
      V result = value;
      this.value = newValue;
      return result;
    }
  }

  private static class KeyList<K, V> {
    Node<K, V> head;
    Node<K, V> tail;
    int count;

    KeyList(Node<K, V> firstNode) {
      this.head = firstNode;
      this.tail = firstNode;
      firstNode.previousSibling = null;
      firstNode.nextSibling = null;
      this.count = 1;
    }
  }

  private transient @Nullable Node<K, V> head; // the head for all keys
  private transient @Nullable Node<K, V> tail; // the tail for all keys
  private transient Map<K, KeyList<K, V>> keyToKeyList;
  private transient int size;

  /*
   * Tracks modifications to keyToKeyList so that addition or removal of keys invalidates
   * preexisting iterators. This does *not* track simple additions and removals of values
   * that are not the first to be added or last to be removed for their key.
   */
  private transient int modCount;

  /** Creates a new, empty {@code LinkedListMultimap} with the default initial capacity. */
  public static <K, V> LinkedListMultimap<K, V> create() {
    return new LinkedListMultimap<>();
  }

  /**
   * Constructs an empty {@code LinkedListMultimap} with enough capacity to hold the specified
   * number of keys without rehashing.
   *
   * @param expectedKeys the expected number of distinct keys
   * @throws IllegalArgumentException if {@code expectedKeys} is negative
   */
  public static <K, V> LinkedListMultimap<K, V> create(int expectedKeys) {
    return new LinkedListMultimap<>(expectedKeys);
  }

  /**
   * Constructs a {@code LinkedListMultimap} with the same mappings as the specified {@code
   * Multimap}. The new multimap has the same {@link Multimap#entries()} iteration order as the
   * input multimap.
   *
   * @param multimap the multimap whose contents are copied to this multimap
   */
  public static <K, V> LinkedListMultimap<K, V> create(
      Multimap<? extends K, ? extends V> multimap) {
    return new LinkedListMultimap<>(multimap);
  }

  LinkedListMultimap() {
    this(12);
  }

  private LinkedListMultimap(int expectedKeys) {
    keyToKeyList = Platform.newHashMapWithExpectedSize(expectedKeys);
  }

  private LinkedListMultimap(Multimap<? extends K, ? extends V> multimap) {
    this(multimap.keySet().size());
    putAll(multimap);
  }

  /**
   * Adds a new node for the specified key-value pair before the specified {@code nextSibling}
   * element, or at the end of the list if {@code nextSibling} is null. Note: if {@code nextSibling}
   * is specified, it MUST be for an node for the same {@code key}!
   */
  @CanIgnoreReturnValue
  private Node<K, V> addNode(@Nullable K key, @Nullable V value, @Nullable Node<K, V> nextSibling) {
    Node<K, V> node = new Node<>(key, value);
    if (head == null) { // empty list
      head = tail = node;
      keyToKeyList.put(key, new KeyList<K, V>(node));
      modCount++;
    } else if (nextSibling == null) { // non-empty list, add to tail
      tail.next = node;
      node.previous = tail;
      tail = node;
      KeyList<K, V> keyList = keyToKeyList.get(key);
      if (keyList == null) {
        keyToKeyList.put(key, keyList = new KeyList<>(node));
        modCount++;
      } else {
        keyList.count++;
        Node<K, V> keyTail = keyList.tail;
        keyTail.nextSibling = node;
        node.previousSibling = keyTail;
        keyList.tail = node;
      }
    } else { // non-empty list, insert before nextSibling
      KeyList<K, V> keyList = keyToKeyList.get(key);
      keyList.count++;
      node.previous = nextSibling.previous;
      node.previousSibling = nextSibling.previousSibling;
      node.next = nextSibling;
      node.nextSibling = nextSibling;
      if (nextSibling.previousSibling == null) { // nextSibling was key head
        keyToKeyList.get(key).head = node;
      } else {
        nextSibling.previousSibling.nextSibling = node;
      }
      if (nextSibling.previous == null) { // nextSibling was head
        head = node;
      } else {
        nextSibling.previous.next = node;
      }
      nextSibling.previous = node;
      nextSibling.previousSibling = node;
    }
    size++;
    return node;
  }

  /**
   * Removes the specified node from the linked list. This method is only intended to be used from
   * the {@code Iterator} classes. See also {@link LinkedListMultimap#removeAllNodes(Object)}.
   */
  private void removeNode(Node<K, V> node) {
    if (node.previous != null) {
      node.previous.next = node.next;
    } else { // node was head
      head = node.next;
    }
    if (node.next != null) {
      node.next.previous = node.previous;
    } else { // node was tail
      tail = node.previous;
    }
    if (node.previousSibling == null && node.nextSibling == null) {
      KeyList<K, V> keyList = keyToKeyList.remove(node.key);
      keyList.count = 0;
      modCount++;
    } else {
      KeyList<K, V> keyList = keyToKeyList.get(node.key);
      keyList.count--;

      if (node.previousSibling == null) {
        keyList.head = node.nextSibling;
      } else {
        node.previousSibling.nextSibling = node.nextSibling;
      }

      if (node.nextSibling == null) {
        keyList.tail = node.previousSibling;
      } else {
        node.nextSibling.previousSibling = node.previousSibling;
      }
    }
    size--;
  }

  /** Removes all nodes for the specified key. */
  private void removeAllNodes(@Nullable Object key) {
    Iterators.clear(new ValueForKeyIterator(key));
  }

  /** Helper method for verifying that an iterator element is present. */
  private static void checkElement(@Nullable Object node) {
    if (node == null) {
      throw new NoSuchElementException();
    }
  }

  /** An {@code Iterator} over all nodes. */
  private class NodeIterator implements ListIterator<Entry<K, V>> {
    int nextIndex;
    @Nullable Node<K, V> next;
    @Nullable Node<K, V> current;
    @Nullable Node<K, V> previous;
    int expectedModCount = modCount;

    NodeIterator(int index) {
      int size = size();
      checkPositionIndex(index, size);
      if (index >= (size / 2)) {
        previous = tail;
        nextIndex = size;
        while (index++ < size) {
          previous();
        }
      } else {
        next = head;
        while (index-- > 0) {
          next();
        }
      }
      current = null;
    }

    private void checkForConcurrentModification() {
      if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
      }
    }

    @Override
    public boolean hasNext() {
      checkForConcurrentModification();
      return next != null;
    }

    @CanIgnoreReturnValue
    @Override
    public Node<K, V> next() {
      checkForConcurrentModification();
      checkElement(next);
      previous = current = next;
      next = next.next;
      nextIndex++;
      return current;
    }

    @Override
    public void remove() {
      checkForConcurrentModification();
      checkRemove(current != null);
      if (current != next) { // after call to next()
        previous = current.previous;
        nextIndex--;
      } else { // after call to previous()
        next = current.next;
      }
      removeNode(current);
      current = null;
      expectedModCount = modCount;
    }

    @Override
    public boolean hasPrevious() {
      checkForConcurrentModification();
      return previous != null;
    }

    @CanIgnoreReturnValue
    @Override
    public Node<K, V> previous() {
      checkForConcurrentModification();
      checkElement(previous);
      next = current = previous;
      previous = previous.previous;
      nextIndex--;
      return current;
    }

    @Override
    public int nextIndex() {
      return nextIndex;
    }

    @Override
    public int previousIndex() {
      return nextIndex - 1;
    }

    @Override
    public void set(Entry<K, V> e) {
      throw new UnsupportedOperationException();
    }

    @Override
    public void add(Entry<K, V> e) {
      throw new UnsupportedOperationException();
    }

    void setValue(V value) {
      checkState(current != null);
      current.value = value;
    }
  }

  /** An {@code Iterator} over distinct keys in key head order. */
  private class DistinctKeyIterator implements Iterator<K> {
    final Set<K> seenKeys = Sets.<K>newHashSetWithExpectedSize(keySet().size());
    Node<K, V> next = head;
    @Nullable Node<K, V> current;
    int expectedModCount = modCount;

    private void checkForConcurrentModification() {
      if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
      }
    }

    @Override
    public boolean hasNext() {
      checkForConcurrentModification();
      return next != null;
    }

    @Override
    public K next() {
      checkForConcurrentModification();
      checkElement(next);
      current = next;
      seenKeys.add(current.key);
      do { // skip ahead to next unseen key
        next = next.next;
      } while ((next != null) && !seenKeys.add(next.key));
      return current.key;
    }

    @Override
    public void remove() {
      checkForConcurrentModification();
      checkRemove(current != null);
      removeAllNodes(current.key);
      current = null;
      expectedModCount = modCount;
    }
  }

  /** A {@code ListIterator} over values for a specified key. */
  private class ValueForKeyIterator implements ListIterator<V> {
    final @Nullable Object key;
    int nextIndex;
    @Nullable Node<K, V> next;
    @Nullable Node<K, V> current;
    @Nullable Node<K, V> previous;

    /** Constructs a new iterator over all values for the specified key. */
    ValueForKeyIterator(@Nullable Object key) {
      this.key = key;
      KeyList<K, V> keyList = keyToKeyList.get(key);
      next = (keyList == null) ? null : keyList.head;
    }

    /**
     * Constructs a new iterator over all values for the specified key starting at the specified
     * index. This constructor is optimized so that it starts at either the head or the tail,
     * depending on which is closer to the specified index. This allows adds to the tail to be done
     * in constant time.
     *
     * @throws IndexOutOfBoundsException if index is invalid
     */
    public ValueForKeyIterator(@Nullable Object key, int index) {
      KeyList<K, V> keyList = keyToKeyList.get(key);
      int size = (keyList == null) ? 0 : keyList.count;
      checkPositionIndex(index, size);
      if (index >= (size / 2)) {
        previous = (keyList == null) ? null : keyList.tail;
        nextIndex = size;
        while (index++ < size) {
          previous();
        }
      } else {
        next = (keyList == null) ? null : keyList.head;
        while (index-- > 0) {
          next();
        }
      }
      this.key = key;
      current = null;
    }

    @Override
    public boolean hasNext() {
      return next != null;
    }

    @CanIgnoreReturnValue
    @Override
    public V next() {
      checkElement(next);
      previous = current = next;
      next = next.nextSibling;
      nextIndex++;
      return current.value;
    }

    @Override
    public boolean hasPrevious() {
      return previous != null;
    }

    @CanIgnoreReturnValue
    @Override
    public V previous() {
      checkElement(previous);
      next = current = previous;
      previous = previous.previousSibling;
      nextIndex--;
      return current.value;
    }

    @Override
    public int nextIndex() {
      return nextIndex;
    }

    @Override
    public int previousIndex() {
      return nextIndex - 1;
    }

    @Override
    public void remove() {
      checkRemove(current != null);
      if (current != next) { // after call to next()
        previous = current.previousSibling;
        nextIndex--;
      } else { // after call to previous()
        next = current.nextSibling;
      }
      removeNode(current);
      current = null;
    }

    @Override
    public void set(V value) {
      checkState(current != null);
      current.value = value;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void add(V value) {
      previous = addNode((K) key, value, next);
      nextIndex++;
      current = null;
    }
  }

  // Query Operations

  @Override
  public int size() {
    return size;
  }

  @Override
  public boolean isEmpty() {
    return head == null;
  }

  @Override
  public boolean containsKey(@Nullable Object key) {
    return keyToKeyList.containsKey(key);
  }

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

  // Modification Operations

  /**
   * Stores a key-value pair in the multimap.
   *
   * @param key key to store in the multimap
   * @param value value to store in the multimap
   * @return {@code true} always
   */
  @CanIgnoreReturnValue
  @Override
  public boolean put(@Nullable K key, @Nullable V value) {
    addNode(key, value, null);
    return true;
  }

  // Bulk Operations

  /**
   * {@inheritDoc}
   *
   *
If any entries for the specified {@code key} already exist in the multimap, their values are
   * changed in-place without affecting the iteration order.
   *
   *
The returned list is immutable and implements {@link java.util.RandomAccess}.
   */
  @CanIgnoreReturnValue
  @Override
  public List<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
    List<V> oldValues = getCopy(key);
    ListIterator<V> keyValues = new ValueForKeyIterator(key);
    Iterator<? extends V> newValues = values.iterator();

    // Replace existing values, if any.
    while (keyValues.hasNext() && newValues.hasNext()) {
      keyValues.next();
      keyValues.set(newValues.next());
    }

    // Remove remaining old values, if any.
    while (keyValues.hasNext()) {
      keyValues.next();
      keyValues.remove();
    }

    // Add remaining new values, if any.
    while (newValues.hasNext()) {
      keyValues.add(newValues.next());
    }

    return oldValues;
  }

  private List<V> getCopy(@Nullable Object key) {
    return unmodifiableList(Lists.newArrayList(new ValueForKeyIterator(key)));
  }

  /**
   * {@inheritDoc}
   *
   *
The returned list is immutable and implements {@link java.util.RandomAccess}.
   */
  @CanIgnoreReturnValue
  @Override
  public List<V> removeAll(@Nullable Object key) {
    List<V> oldValues = getCopy(key);
    removeAllNodes(key);
    return oldValues;
  }

  @Override
  public void clear() {
    head = null;
    tail = null;
    keyToKeyList.clear();
    size = 0;
    modCount++;
  }

  // Views

  /**
   * {@inheritDoc}
   *
   *
If the multimap is modified while an iteration over the list is in progress (except through
   * the iterator's own {@code add}, {@code set} or {@code remove} operations) the results of the
   * iteration are undefined.
   *
   *
The returned list is not serializable and does not have random access.
   */
  @Override
  public List<V> get(final @Nullable K key) {
    return new AbstractSequentialList<V>() {
      @Override
      public int size() {
        KeyList<K, V> keyList = keyToKeyList.get(key);
        return (keyList == null) ? 0 : keyList.count;
      }

      @Override
      public ListIterator<V> listIterator(int index) {
        return new ValueForKeyIterator(key, index);
      }
    };
  }

  @Override
  Set<K> createKeySet() {
    @WeakOuter
    class KeySetImpl extends Sets.ImprovedAbstractSet<K> {
      @Override
      public int size() {
        return keyToKeyList.size();
      }

      @Override
      public Iterator<K> iterator() {
        return new DistinctKeyIterator();
      }

      @Override
      public boolean contains(Object key) { // for performance
        return containsKey(key);
      }

      @Override
      public boolean remove(Object o) { // for performance
        return !LinkedListMultimap.this.removeAll(o).isEmpty();
      }
    }
    return new KeySetImpl();
  }

  @Override
  Multiset<K> createKeys() {
    return new Multimaps.Keys<K, V>(this);
  }

  /**
   * {@inheritDoc}
   *
   *
The iterator generated by the returned collection traverses the values in the order they
   * were added to the multimap. Because the values may have duplicates and follow the insertion
   * ordering, this method returns a {@link List}, instead of the {@link Collection} specified in
   * the {@link ListMultimap} interface.
   */
  @Override
  public List<V> values() {
    return (List<V>) super.values();
  }

  @Override
  List<V> createValues() {
    @WeakOuter
    class ValuesImpl extends AbstractSequentialList<V> {
      @Override
      public int size() {
        return size;
      }

      @Override
      public ListIterator<V> listIterator(int index) {
        final NodeIterator nodeItr = new NodeIterator(index);
        return new TransformedListIterator<Entry<K, V>, V>(nodeItr) {
          @Override
          V transform(Entry<K, V> entry) {
            return entry.getValue();
          }

          @Override
          public void set(V value) {
            nodeItr.setValue(value);
          }
        };
      }
    }
    return new ValuesImpl();
  }

  /**
   * {@inheritDoc}
   *
   *
The iterator generated by the returned collection traverses the entries in the order they
   * were added to the multimap. Because the entries may have duplicates and follow the insertion
   * ordering, this method returns a {@link List}, instead of the {@link Collection} specified in
   * the {@link ListMultimap} interface.
   *
   *
An entry's {@link Entry#getKey} method always returns the same key, regardless of what
   * happens subsequently. As long as the corresponding key-value mapping is not removed from the
   * multimap, {@link Entry#getValue} returns the value from the multimap, which may change over
   * time, and {@link Entry#setValue} modifies that value. Removing the mapping from the multimap
   * does not alter the value returned by {@code getValue()}, though a subsequent {@code setValue()}
   * call won't update the multimap but will lead to a revised value being returned by {@code
   * getValue()}.
   */
  @Override
  public List<Entry<K, V>> entries() {
    return (List<Entry<K, V>>) super.entries();
  }

  @Override
  List<Entry<K, V>> createEntries() {
    @WeakOuter
    class EntriesImpl extends AbstractSequentialList<Entry<K, V>> {
      @Override
      public int size() {
        return size;
      }

      @Override
      public ListIterator<Entry<K, V>> listIterator(int index) {
        return new NodeIterator(index);
      }

      @Override
      public void forEach(Consumer<? super Entry<K, V>> action) {
        checkNotNull(action);
        for (Node<K, V> node = head; node != null; node = node.next) {
          action.accept(node);
        }
      }
    }
    return new EntriesImpl();
  }

  @Override
  Iterator<Entry<K, V>> entryIterator() {
    throw new AssertionError("should never be called");
  }

  @Override
  Map<K, Collection<V>> createAsMap() {
    return new Multimaps.AsMap<>(this);
  }

  /**
   * @serialData the number of distinct keys, and then for each distinct key: the first key, the
   *     number of values for that key, and the key's values, followed by successive keys and values
   *     from the entries() ordering
   */
  @GwtIncompatible // java.io.ObjectOutputStream
  private void writeObject(ObjectOutputStream stream) throws IOException {
    stream.defaultWriteObject();
    stream.writeInt(size());
    for (Entry<K, V> entry : entries()) {
      stream.writeObject(entry.getKey());
      stream.writeObject(entry.getValue());
    }
  }

  @GwtIncompatible // java.io.ObjectInputStream
  private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    stream.defaultReadObject();
    keyToKeyList = Maps.newLinkedHashMap();
    int size = stream.readInt();
    for (int i = 0; i < size; i++) {
      @SuppressWarnings("unchecked") // reading data stored by writeObject
      K key = (K) stream.readObject();
      @SuppressWarnings("unchecked") // reading data stored by writeObject
      V value = (V) stream.readObject();
      put(key, value);
    }
  }

  @GwtIncompatible // java serialization not supported
  private static final long serialVersionUID = 0;
}


/*
 * Copyright (C) 2013 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.hash;

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

import com.google.common.annotations.Beta;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * An {@link InputStream} that maintains a hash of the data read from it.
 *
 * @author Qian Huang
 * @since 16.0
 */
@Beta
public final class HashingInputStream extends FilterInputStream {
  private final Hasher hasher;

  /**
   * Creates an input stream that hashes using the given {@link HashFunction} and delegates all data
   * read from it to the underlying {@link InputStream}.
   *
   * <p>The {@link InputStream} should not be read from before or after the hand-off.
   */
  public HashingInputStream(HashFunction hashFunction, InputStream in) {
    super(checkNotNull(in));
    this.hasher = checkNotNull(hashFunction.newHasher());
  }

  /**
   * Reads the next byte of data from the underlying input stream and updates the hasher with the
   * byte read.
   */
  @Override
  @CanIgnoreReturnValue
  public int read() throws IOException {
    int b = in.read();
    if (b != -1) {
      hasher.putByte((byte) b);
    }
    return b;
  }

  /**
   * Reads the specified bytes of data from the underlying input stream and updates the hasher with
   * the bytes read.
   */
  @Override
  @CanIgnoreReturnValue
  public int read(byte[] bytes, int off, int len) throws IOException {
    int numOfBytesRead = in.read(bytes, off, len);
    if (numOfBytesRead != -1) {
      hasher.putBytes(bytes, off, numOfBytesRead);
    }
    return numOfBytesRead;
  }

  /**
   * mark() is not supported for HashingInputStream
   *
   * @return {@code false} always
   */
  @Override
  public boolean markSupported() {
    return false;
  }

  /** mark() is not supported for HashingInputStream */
  @Override
  public void mark(int readlimit) {}

  /**
   * reset() is not supported for HashingInputStream.
   *
   * @throws IOException this operation is not supported
   */
  @Override
  public void reset() throws IOException {
    throw new IOException("reset not supported");
  }

  /**
   * Returns the {@link HashCode} based on the data read from this stream. The result is unspecified
   * if this method is called more than once on the same instance.
   */
  public HashCode hash() {
    return hasher.hash();
  }
}


/*
 * 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 com.google.common.annotations.GwtIncompatible;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;

/**
 * Provides static methods for serializing collection classes.
 *
 *
This class assists the implementation of collection classes. Do not use this class to
 * serialize collections that are defined elsewhere.
 *
 * @author Jared Levy
 */
@GwtIncompatible
final class Serialization {
  private Serialization() {}

  /**
   * Reads a count corresponding to a serialized map, multiset, or multimap. It returns the size of
   * a map serialized by {@link #writeMap(Map, ObjectOutputStream)}, the number of distinct elements
   * in a multiset serialized by {@link #writeMultiset(Multiset, ObjectOutputStream)}, or the number
   * of distinct keys in a multimap serialized by {@link #writeMultimap(Multimap,
   * ObjectOutputStream)}.
   */
  static int readCount(ObjectInputStream stream) throws IOException {
    return stream.readInt();
  }

  /**
   * Stores the contents of a map in an output stream, as part of serialization. It does not support
   * concurrent maps whose content may change while the method is running.
   *
   *
The serialized output consists of the number of entries, first key, first value, second key,
   * second value, and so on.
   */
  static <K, V> void writeMap(Map<K, V> map, ObjectOutputStream stream) throws IOException {
    stream.writeInt(map.size());
    for (Map.Entry<K, V> entry : map.entrySet()) {
      stream.writeObject(entry.getKey());
      stream.writeObject(entry.getValue());
    }
  }

  /**
   * Populates a map by reading an input stream, as part of deserialization. See {@link #writeMap}
   * for the data format.
   */
  static <K, V> void populateMap(Map<K, V> map, ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    int size = stream.readInt();
    populateMap(map, stream, size);
  }

  /**
   * Populates a map by reading an input stream, as part of deserialization. See {@link #writeMap}
   * for the data format. The size is determined by a prior call to {@link #readCount}.
   */
  static <K, V> void populateMap(Map<K, V> map, ObjectInputStream stream, int size)
      throws IOException, ClassNotFoundException {
    for (int i = 0; i < size; i++) {
      @SuppressWarnings("unchecked") // reading data stored by writeMap
      K key = (K) stream.readObject();
      @SuppressWarnings("unchecked") // reading data stored by writeMap
      V value = (V) stream.readObject();
      map.put(key, value);
    }
  }

  /**
   * Stores the contents of a multiset in an output stream, as part of serialization. It does not
   * support concurrent multisets whose content may change while the method is running.
   *
   *
The serialized output consists of the number of distinct elements, the first element, its
   * count, the second element, its count, and so on.
   */
  static <E> void writeMultiset(Multiset<E> multiset, ObjectOutputStream stream)
      throws IOException {
    int entryCount = multiset.entrySet().size();
    stream.writeInt(entryCount);
    for (Multiset.Entry<E> entry : multiset.entrySet()) {
      stream.writeObject(entry.getElement());
      stream.writeInt(entry.getCount());
    }
  }

  /**
   * Populates a multiset by reading an input stream, as part of deserialization. See {@link
   * #writeMultiset} for the data format.
   */
  static <E> void populateMultiset(Multiset<E> multiset, ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    int distinctElements = stream.readInt();
    populateMultiset(multiset, stream, distinctElements);
  }

  /**
   * Populates a multiset by reading an input stream, as part of deserialization. See {@link
   * #writeMultiset} for the data format. The number of distinct elements is determined by a prior
   * call to {@link #readCount}.
   */
  static <E> void populateMultiset(
      Multiset<E> multiset, ObjectInputStream stream, int distinctElements)
      throws IOException, ClassNotFoundException {
    for (int i = 0; i < distinctElements; i++) {
      @SuppressWarnings("unchecked") // reading data stored by writeMultiset
      E element = (E) stream.readObject();
      int count = stream.readInt();
      multiset.add(element, count);
    }
  }

  /**
   * Stores the contents of a multimap in an output stream, as part of serialization. It does not
   * support concurrent multimaps whose content may change while the method is running. The {@link
   * Multimap#asMap} view determines the ordering in which data is written to the stream.
   *
   *
The serialized output consists of the number of distinct keys, and then for each distinct
   * key: the key, the number of values for that key, and the key's values.
   */
  static <K, V> void writeMultimap(Multimap<K, V> multimap, ObjectOutputStream stream)
      throws IOException {
    stream.writeInt(multimap.asMap().size());
    for (Map.Entry<K, Collection<V>> entry : multimap.asMap().entrySet()) {
      stream.writeObject(entry.getKey());
      stream.writeInt(entry.getValue().size());
      for (V value : entry.getValue()) {
        stream.writeObject(value);
      }
    }
  }

  /**
   * Populates a multimap by reading an input stream, as part of deserialization. See {@link
   * #writeMultimap} for the data format.
   */
  static <K, V> void populateMultimap(Multimap<K, V> multimap, ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    int distinctKeys = stream.readInt();
    populateMultimap(multimap, stream, distinctKeys);
  }

  /**
   * Populates a multimap by reading an input stream, as part of deserialization. See {@link
   * #writeMultimap} for the data format. The number of distinct keys is determined by a prior call
   * to {@link #readCount}.
   */
  static <K, V> void populateMultimap(
      Multimap<K, V> multimap, ObjectInputStream stream, int distinctKeys)
      throws IOException, ClassNotFoundException {
    for (int i = 0; i < distinctKeys; i++) {
      @SuppressWarnings("unchecked") // reading data stored by writeMultimap
      K key = (K) stream.readObject();
      Collection<V> values = multimap.get(key);
      int valueCount = stream.readInt();
      for (int j = 0; j < valueCount; j++) {
        @SuppressWarnings("unchecked") // reading data stored by writeMultimap
        V value = (V) stream.readObject();
        values.add(value);
      }
    }
  }

  // Secret sauce for setting final fields; don't make it public.
  static <T> FieldSetter<T> getFieldSetter(final Class<T> clazz, String fieldName) {
    try {
      Field field = clazz.getDeclaredField(fieldName);
      return new FieldSetter<T>(field);
    } catch (NoSuchFieldException e) {
      throw new AssertionError(e); // programmer error
    }
  }

  // Secret sauce for setting final fields; don't make it public.
  static final class FieldSetter<T> {
    private final Field field;

    private FieldSetter(Field field) {
      this.field = field;
      field.setAccessible(true);
    }

    void set(T instance, Object value) {
      try {
        field.set(instance, value);
      } catch (IllegalAccessException impossible) {
        throw new AssertionError(impossible);
      }
    }

    void set(T instance, int value) {
      try {
        field.set(instance, value);
      } catch (IllegalAccessException impossible) {
        throw new AssertionError(impossible);
      }
    }
  }
}


/*
 * Copyright (C) 2016 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.graph;

import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A {@link MapIteratorCache} that adds additional caching. In addition to the caching provided by
 * {@link MapIteratorCache}, this structure caches values for the two most recently retrieved keys.
 *
 * @author James Sexton
 */
class MapRetrievalCache<K, V> extends MapIteratorCache<K, V> {
  private transient @Nullable CacheEntry<K, V> cacheEntry1;
  private transient @Nullable CacheEntry<K, V> cacheEntry2;

  MapRetrievalCache(Map<K, V> backingMap) {
    super(backingMap);
  }

  @SuppressWarnings("unchecked") // Safe because we only cast if key is found in map.
  @Override
  public V get(@Nullable Object key) {
    V value = getIfCached(key);
    if (value != null) {
      return value;
    }

    value = getWithoutCaching(key);
    if (value != null) {
      addToCache((K) key, value);
    }
    return value;
  }

  // Internal methods ('protected' is still package-visible, but treat as only subclass-visible)

  @Override
  protected V getIfCached(@Nullable Object key) {
    V value = super.getIfCached(key);
    if (value != null) {
      return value;
    }

    // Store a local reference to the cache entry. If the backing map is immutable, this,
    // in combination with immutable cache entries, will ensure a thread-safe cache.
    CacheEntry<K, V> entry;

    // Check cache. We use == on purpose because it's cheaper and a cache miss is ok.
    entry = cacheEntry1;
    if (entry != null && entry.key == key) {
      return entry.value;
    }
    entry = cacheEntry2;
    if (entry != null && entry.key == key) {
      // Promote second cache entry to first so the access pattern
      // [K1, K2, K1, K3, K1, K4...] still hits the cache half the time.
      addToCache(entry);
      return entry.value;
    }
    return null;
  }

  @Override
  protected void clearCache() {
    super.clearCache();
    cacheEntry1 = null;
    cacheEntry2 = null;
  }

  private void addToCache(K key, V value) {
    addToCache(new CacheEntry<K, V>(key, value));
  }

  private void addToCache(CacheEntry<K, V> entry) {
    // Slide new entry into first cache position. Drop previous entry in second cache position.
    cacheEntry2 = cacheEntry1;
    cacheEntry1 = entry;
  }

  private static final class CacheEntry<K, V> {
    final K key;
    final V value;

    CacheEntry(K key, V value) {
      this.key = key;
      this.value = value;
    }
  }
}