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

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

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * A convenience base class for implementors of {@code Hasher}; handles accumulating data until an
 * entire "chunk" (of implementation-dependent length) is ready to be hashed.
 *
 * @author Kevin Bourrillion
 * @author Dimitris Andreou
 */
// TODO(kevinb): this class still needs some design-and-document-for-inheritance love
@CanIgnoreReturnValue
abstract class AbstractStreamingHasher extends AbstractHasher {
  /** Buffer via which we pass data to the hash algorithm (the implementor) */
  private final ByteBuffer buffer;

  /** Number of bytes to be filled before process() invocation(s). */
  private final int bufferSize;

  /** Number of bytes processed per process() invocation. */
  private final int chunkSize;

  /**
   * Constructor for use by subclasses. This hasher instance will process chunks of the specified
   * size.
   *
   * @param chunkSize the number of bytes available per {@link #process(ByteBuffer)} invocation;
   *     must be at least 4
   */
  protected AbstractStreamingHasher(int chunkSize) {
    this(chunkSize, chunkSize);
  }

  /**
   * Constructor for use by subclasses. This hasher instance will process chunks of the specified
   * size, using an internal buffer of {@code bufferSize} size, which must be a multiple of {@code
   * chunkSize}.
   *
   * @param chunkSize the number of bytes available per {@link #process(ByteBuffer)} invocation;
   *     must be at least 4
   * @param bufferSize the size of the internal buffer. Must be a multiple of chunkSize
   */
  protected AbstractStreamingHasher(int chunkSize, int bufferSize) {
    // TODO(kevinb): check more preconditions (as bufferSize >= chunkSize) if this is ever public
    checkArgument(bufferSize % chunkSize == 0);

    // TODO(user): benchmark performance difference with longer buffer
    // always space for a single primitive
    this.buffer = ByteBuffer.allocate(bufferSize + 7).order(ByteOrder.LITTLE_ENDIAN);
    this.bufferSize = bufferSize;
    this.chunkSize = chunkSize;
  }

  /** Processes the available bytes of the buffer (at most {@code chunk} bytes). */
  protected abstract void process(ByteBuffer bb);

  /**
   * This is invoked for the last bytes of the input, which are not enough to fill a whole chunk.
   * The passed {@code ByteBuffer} is guaranteed to be non-empty.
   *
   * <p>This implementation simply pads with zeros and delegates to {@link #process(ByteBuffer)}.
   */
  protected void processRemaining(ByteBuffer bb) {
    bb.position(bb.limit()); // move at the end
    bb.limit(chunkSize + 7); // get ready to pad with longs
    while (bb.position() < chunkSize) {
      bb.putLong(0);
    }
    bb.limit(chunkSize);
    bb.flip();
    process(bb);
  }

  @Override
  public final Hasher putBytes(byte[] bytes, int off, int len) {
    return putBytesInternal(ByteBuffer.wrap(bytes, off, len).order(ByteOrder.LITTLE_ENDIAN));
  }

  @Override
  public final Hasher putBytes(ByteBuffer readBuffer) {
    ByteOrder order = readBuffer.order();
    try {
      readBuffer.order(ByteOrder.LITTLE_ENDIAN);
      return putBytesInternal(readBuffer);
    } finally {
      readBuffer.order(order);
    }
  }

  private Hasher putBytesInternal(ByteBuffer readBuffer) {
    // If we have room for all of it, this is easy
    if (readBuffer.remaining() <= buffer.remaining()) {
      buffer.put(readBuffer);
      munchIfFull();
      return this;
    }

    // First add just enough to fill buffer size, and munch that
    int bytesToCopy = bufferSize - buffer.position();
    for (int i = 0; i < bytesToCopy; i++) {
      buffer.put(readBuffer.get());
    }
    munch(); // buffer becomes empty here, since chunkSize divides bufferSize

    // Now process directly from the rest of the input buffer
    while (readBuffer.remaining() >= chunkSize) {
      process(readBuffer);
    }

    // Finally stick the remainder back in our usual buffer
    buffer.put(readBuffer);
    return this;
  }

  /*
   * Note: hashString(CharSequence, Charset) is intentionally not overridden.
   *
   * While intuitively, using CharsetEncoder to encode the CharSequence directly to the buffer (or
   * even to an intermediate buffer) should be considerably more efficient than potentially
   * copying the CharSequence to a String and then calling getBytes(Charset) on that String, in
   * reality there are optimizations that make the getBytes(Charset) approach considerably faster,
   * at least for commonly used charsets like UTF-8.
   */

  @Override
  public final Hasher putByte(byte b) {
    buffer.put(b);
    munchIfFull();
    return this;
  }

  @Override
  public final Hasher putShort(short s) {
    buffer.putShort(s);
    munchIfFull();
    return this;
  }

  @Override
  public final Hasher putChar(char c) {
    buffer.putChar(c);
    munchIfFull();
    return this;
  }

  @Override
  public final Hasher putInt(int i) {
    buffer.putInt(i);
    munchIfFull();
    return this;
  }

  @Override
  public final Hasher putLong(long l) {
    buffer.putLong(l);
    munchIfFull();
    return this;
  }

  @Override
  public final HashCode hash() {
    munch();
    buffer.flip();
    if (buffer.remaining() > 0) {
      processRemaining(buffer);
      buffer.position(buffer.limit());
    }
    return makeHash();
  }

  /**
   * Computes a hash code based on the data that have been provided to this hasher. This is called
   * after all chunks are handled with {@link #process} and any leftover bytes that did not make a
   * complete chunk are handled with {@link #processRemaining}.
   */
  protected abstract HashCode makeHash();

  // Process pent-up data in chunks
  private void munchIfFull() {
    if (buffer.remaining() < 8) {
      // buffer is full; not enough room for a primitive. We have at least one full chunk.
      munch();
    }
  }

  private void munch() {
    buffer.flip();
    while (buffer.remaining() >= chunkSize) {
      // we could limit the buffer to ensure process() does not read more than
      // chunkSize number of bytes, but we trust the implementations
      process(buffer);
    }
    buffer.compact(); // preserve any remaining data that do not make a full chunk
  }
}


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

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

import com.google.common.annotations.GwtCompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.Serializable;
import java.math.BigInteger;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * A wrapper class for unsigned {@code long} values, supporting arithmetic operations.
 *
 *
In some cases, when speed is more important than code readability, it may be faster simply to
 * treat primitive {@code long} values as unsigned, using the methods from {@link UnsignedLongs}.
 *
 *
See the Guava User Guide article on unsigned
 * primitive utilities.
 *
 * @author Louis Wasserman
 * @author Colin Evans
 * @since 11.0
 */
@GwtCompatible(serializable = true)
public final class UnsignedLong extends Number implements Comparable<UnsignedLong>, Serializable {

  private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;

  public static final UnsignedLong ZERO = new UnsignedLong(0);
  public static final UnsignedLong ONE = new UnsignedLong(1);
  public static final UnsignedLong MAX_VALUE = new UnsignedLong(-1L);

  private final long value;

  private UnsignedLong(long value) {
    this.value = value;
  }

  /**
   * Returns an {@code UnsignedLong} corresponding to a given bit representation. The argument is
   * interpreted as an unsigned 64-bit value. Specifically, the sign bit of {@code bits} is
   * interpreted as a normal bit, and all other bits are treated as usual.
   *
   *
If the argument is nonnegative, the returned result will be equal to {@code bits},
   * otherwise, the result will be equal to {@code 2^64 + bits}.
   *
   *
To represent decimal constants less than {@code 2^63}, consider {@link #valueOf(long)}
   * instead.
   *
   * @since 14.0
   */
  public static UnsignedLong fromLongBits(long bits) {
    // TODO(lowasser): consider caching small values, like Long.valueOf
    return new UnsignedLong(bits);
  }

  /**
   * Returns an {@code UnsignedLong} representing the same value as the specified {@code long}.
   *
   * @throws IllegalArgumentException if {@code value} is negative
   * @since 14.0
   */
  @CanIgnoreReturnValue
  public static UnsignedLong valueOf(long value) {
    checkArgument(value >= 0, "value (%s) is outside the range for an unsigned long value", value);
    return fromLongBits(value);
  }

  /**
   * Returns a {@code UnsignedLong} representing the same value as the specified {@code BigInteger}.
   * This is the inverse operation of {@link #bigIntegerValue()}.
   *
   * @throws IllegalArgumentException if {@code value} is negative or {@code value >= 2^64}
   */
  @CanIgnoreReturnValue
  public static UnsignedLong valueOf(BigInteger value) {
    checkNotNull(value);
    checkArgument(
        value.signum() >= 0 && value.bitLength() <= Long.SIZE,
        "value (%s) is outside the range for an unsigned long value",
        value);
    return fromLongBits(value.longValue());
  }

  /**
   * Returns an {@code UnsignedLong} holding the value of the specified {@code String}, parsed as an
   * unsigned {@code long} value.
   *
   * @throws NumberFormatException if the string does not contain a parsable unsigned {@code long}
   *     value
   */
  @CanIgnoreReturnValue
  public static UnsignedLong valueOf(String string) {
    return valueOf(string, 10);
  }

  /**
   * Returns an {@code UnsignedLong} holding the value of the specified {@code String}, parsed as an
   * unsigned {@code long} value in the specified radix.
   *
   * @throws NumberFormatException if the string does not contain a parsable unsigned {@code long}
   *     value, or {@code radix} is not between {@link Character#MIN_RADIX} and {@link
   *     Character#MAX_RADIX}
   */
  @CanIgnoreReturnValue
  public static UnsignedLong valueOf(String string, int radix) {
    return fromLongBits(UnsignedLongs.parseUnsignedLong(string, radix));
  }

  /**
   * Returns the result of adding this and {@code val}. If the result would have more than 64 bits,
   * returns the low 64 bits of the result.
   *
   * @since 14.0
   */
  public UnsignedLong plus(UnsignedLong val) {
    return fromLongBits(this.value + checkNotNull(val).value);
  }

  /**
   * Returns the result of subtracting this and {@code val}. If the result would have more than 64
   * bits, returns the low 64 bits of the result.
   *
   * @since 14.0
   */
  public UnsignedLong minus(UnsignedLong val) {
    return fromLongBits(this.value - checkNotNull(val).value);
  }

  /**
   * Returns the result of multiplying this and {@code val}. If the result would have more than 64
   * bits, returns the low 64 bits of the result.
   *
   * @since 14.0
   */
  public UnsignedLong times(UnsignedLong val) {
    return fromLongBits(value * checkNotNull(val).value);
  }

  /**
   * Returns the result of dividing this by {@code val}.
   *
   * @since 14.0
   */
  public UnsignedLong dividedBy(UnsignedLong val) {
    return fromLongBits(UnsignedLongs.divide(value, checkNotNull(val).value));
  }

  /**
   * Returns this modulo {@code val}.
   *
   * @since 14.0
   */
  public UnsignedLong mod(UnsignedLong val) {
    return fromLongBits(UnsignedLongs.remainder(value, checkNotNull(val).value));
  }

  /** Returns the value of this {@code UnsignedLong} as an {@code int}. */
  @Override
  public int intValue() {
    return (int) value;
  }

  /**
   * Returns the value of this {@code UnsignedLong} as a {@code long}. This is an inverse operation
   * to {@link #fromLongBits}.
   *
   *
Note that if this {@code UnsignedLong} holds a value {@code >= 2^63}, the returned value
   * will be equal to {@code this - 2^64}.
   */
  @Override
  public long longValue() {
    return value;
  }

  /**
   * Returns the value of this {@code UnsignedLong} as a {@code float}, analogous to a widening
   * primitive conversion from {@code long} to {@code float}, and correctly rounded.
   */
  @Override
  public float floatValue() {
    @SuppressWarnings("cast")
    float fValue = (float) (value & UNSIGNED_MASK);
    if (value < 0) {
      fValue += 0x1.0p63f;
    }
    return fValue;
  }

  /**
   * Returns the value of this {@code UnsignedLong} as a {@code double}, analogous to a widening
   * primitive conversion from {@code long} to {@code double}, and correctly rounded.
   */
  @Override
  public double doubleValue() {
    @SuppressWarnings("cast")
    double dValue = (double) (value & UNSIGNED_MASK);
    if (value < 0) {
      dValue += 0x1.0p63;
    }
    return dValue;
  }

  /** Returns the value of this {@code UnsignedLong} as a {@link BigInteger}. */
  public BigInteger bigIntegerValue() {
    BigInteger bigInt = BigInteger.valueOf(value & UNSIGNED_MASK);
    if (value < 0) {
      bigInt = bigInt.setBit(Long.SIZE - 1);
    }
    return bigInt;
  }

  @Override
  public int compareTo(UnsignedLong o) {
    checkNotNull(o);
    return UnsignedLongs.compare(value, o.value);
  }

  @Override
  public int hashCode() {
    return Longs.hashCode(value);
  }

  @Override
  public boolean equals(@NullableDecl Object obj) {
    if (obj instanceof UnsignedLong) {
      UnsignedLong other = (UnsignedLong) obj;
      return value == other.value;
    }
    return false;
  }

  /** Returns a string representation of the {@code UnsignedLong} value, in base 10. */
  @Override
  public String toString() {
    return UnsignedLongs.toString(value);
  }

  /**
   * Returns a string representation of the {@code UnsignedLong} value, in base {@code radix}. If
   * {@code radix < Character.MIN_RADIX} or {@code radix > Character.MAX_RADIX}, the radix {@code
   * 10} is used.
   */
  public String toString(int radix) {
    return UnsignedLongs.toString(value, radix);
  }
}


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

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * Static utility methods pertaining to instances of {@link Throwable}.
 *
 *
See the Guava User Guide entry on Throwables.
 *
 * @author Kevin Bourrillion
 * @author Ben Yu
 * @since 1.0
 */
@GwtCompatible(emulated = true)
public final class Throwables {
  private Throwables() {}

  /**
   * Throws {@code throwable} if it is an instance of {@code declaredType}. Example usage:
   *
   *

   * for (Foo foo : foos) {
   *   try {
   *     foo.bar();
   *   } catch (BarException | RuntimeException | Error t) {
   *     failure = t;
   *   }
   * }
   * if (failure != null) {
   *   throwIfInstanceOf(failure, BarException.class);
   *   throwIfUnchecked(failure);
   *   throw new AssertionError(failure);
   * }
   *

   *
   * @since 20.0
   */
  @GwtIncompatible // Class.cast, Class.isInstance
  public static <X extends Throwable> void throwIfInstanceOf(
      Throwable throwable, Class<X> declaredType) throws X {
    checkNotNull(throwable);
    if (declaredType.isInstance(throwable)) {
      throw declaredType.cast(throwable);
    }
  }

  /**
   * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@code
   * declaredType}. Example usage:
   *
   *

   * try {
   *   someMethodThatCouldThrowAnything();
   * } catch (IKnowWhatToDoWithThisException e) {
   *   handle(e);
   * } catch (Throwable t) {
   *   Throwables.propagateIfInstanceOf(t, IOException.class);
   *   Throwables.propagateIfInstanceOf(t, SQLException.class);
   *   throw Throwables.propagate(t);
   * }
   *

   *
   * @deprecated Use {@link #throwIfInstanceOf}, which has the same behavior but rejects {@code
   *     null}.
   */
  @Deprecated
  @GwtIncompatible // throwIfInstanceOf
  public static <X extends Throwable> void propagateIfInstanceOf(
      @Nullable Throwable throwable, Class<X> declaredType) throws X {
    if (throwable != null) {
      throwIfInstanceOf(throwable, declaredType);
    }
  }

  /**
   * Throws {@code throwable} if it is a {@link RuntimeException} or {@link Error}. Example usage:
   *
   *

   * for (Foo foo : foos) {
   *   try {
   *     foo.bar();
   *   } catch (RuntimeException | Error t) {
   *     failure = t;
   *   }
   * }
   * if (failure != null) {
   *   throwIfUnchecked(failure);
   *   throw new AssertionError(failure);
   * }
   *

   *
   * @since 20.0
   */
  public static void throwIfUnchecked(Throwable throwable) {
    checkNotNull(throwable);
    if (throwable instanceof RuntimeException) {
      throw (RuntimeException) throwable;
    }
    if (throwable instanceof Error) {
      throw (Error) throwable;
    }
  }

  /**
   * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@link
   * RuntimeException} or {@link Error}. Example usage:
   *
   *

   * try {
   *   someMethodThatCouldThrowAnything();
   * } catch (IKnowWhatToDoWithThisException e) {
   *   handle(e);
   * } catch (Throwable t) {
   *   Throwables.propagateIfPossible(t);
   *   throw new RuntimeException("unexpected", t);
   * }
   *

   *
   * @deprecated Use {@link #throwIfUnchecked}, which has the same behavior but rejects {@code
   *     null}.
   */
  @Deprecated
  @GwtIncompatible
  public static void propagateIfPossible(@Nullable Throwable throwable) {
    if (throwable != null) {
      throwIfUnchecked(throwable);
    }
  }

  /**
   * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@link
   * RuntimeException}, {@link Error}, or {@code declaredType}. Example usage:
   *
   *

   * try {
   *   someMethodThatCouldThrowAnything();
   * } catch (IKnowWhatToDoWithThisException e) {
   *   handle(e);
   * } catch (Throwable t) {
   *   Throwables.propagateIfPossible(t, OtherException.class);
   *   throw new RuntimeException("unexpected", t);
   * }
   *

   *
   * @param throwable the Throwable to possibly propagate
   * @param declaredType the single checked exception type declared by the calling method
   */
  @GwtIncompatible // propagateIfInstanceOf
  public static <X extends Throwable> void propagateIfPossible(
      @Nullable Throwable throwable, Class<X> declaredType) throws X {
    propagateIfInstanceOf(throwable, declaredType);
    propagateIfPossible(throwable);
  }

  /**
   * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@link
   * RuntimeException}, {@link Error}, {@code declaredType1}, or {@code declaredType2}. In the
   * unlikely case that you have three or more declared checked exception types, you can handle them
   * all by invoking these methods repeatedly. See usage example in {@link
   * #propagateIfPossible(Throwable, Class)}.
   *
   * @param throwable the Throwable to possibly propagate
   * @param declaredType1 any checked exception type declared by the calling method
   * @param declaredType2 any other checked exception type declared by the calling method
   */
  @GwtIncompatible // propagateIfInstanceOf
  public static <X1 extends Throwable, X2 extends Throwable> void propagateIfPossible(
      @Nullable Throwable throwable, Class<X1> declaredType1, Class<X2> declaredType2)
      throws X1, X2 {
    checkNotNull(declaredType2);
    propagateIfInstanceOf(throwable, declaredType1);
    propagateIfPossible(throwable, declaredType2);
  }

  /**
   * Propagates {@code throwable} as-is if it is an instance of {@link RuntimeException} or {@link
   * Error}, or else as a last resort, wraps it in a {@code RuntimeException} and then propagates.
   *
   *
This method always throws an exception. The {@code RuntimeException} return type allows
   * client code to signal to the compiler that statements after the call are unreachable. Example
   * usage:
   *
   *

   * T doSomething() {
   *   try {
   *     return someMethodThatCouldThrowAnything();
   *   } catch (IKnowWhatToDoWithThisException e) {
   *     return handle(e);
   *   } catch (Throwable t) {
   *     throw Throwables.propagate(t);
   *   }
   * }
   *

   *
   * @param throwable the Throwable to propagate
   * @return nothing will ever be returned; this return type is only for your convenience, as
   *     illustrated in the example above
   * @deprecated Use {@code throw e} or {@code throw new RuntimeException(e)} directly, or use a
   *     combination of {@link #throwIfUnchecked} and {@code throw new RuntimeException(e)}. For
   *     background on the deprecation, read Why we deprecated
   *     {@code Throwables.propagate}.
   */
  @CanIgnoreReturnValue
  @GwtIncompatible
  @Deprecated
  public static RuntimeException propagate(Throwable throwable) {
    throwIfUnchecked(throwable);
    throw new RuntimeException(throwable);
  }

  /**
   * Returns the innermost cause of {@code throwable}. The first throwable in a chain provides
   * context from when the error or exception was initially detected. Example usage:
   *
   *

   * assertEquals("Unable to assign a customer id", Throwables.getRootCause(e).getMessage());
   *

   *
   * @throws IllegalArgumentException if there is a loop in the causal chain
   */
  public static Throwable getRootCause(Throwable throwable) {
    // Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
    // the slower pointer, then there's a loop.
    Throwable slowPointer = throwable;
    boolean advanceSlowPointer = false;

    Throwable cause;
    while ((cause = throwable.getCause()) != null) {
      throwable = cause;

      if (throwable == slowPointer) {
        throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
      }
      if (advanceSlowPointer) {
        slowPointer = slowPointer.getCause();
      }
      advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
    }
    return throwable;
  }

  /**
   * Gets a {@code Throwable} cause chain as a list. The first entry in the list will be {@code
   * throwable} followed by its cause hierarchy. Note that this is a snapshot of the cause chain and
   * will not reflect any subsequent changes to the cause chain.
   *
   *
Here's an example of how it can be used to find specific types of exceptions in the cause
   * chain:
   *
   *

   * Iterables.filter(Throwables.getCausalChain(e), IOException.class));
   *

   *
   * @param throwable the non-null {@code Throwable} to extract causes from
   * @return an unmodifiable list containing the cause chain starting with {@code throwable}
   * @throws IllegalArgumentException if there is a loop in the causal chain
   */
  @Beta // TODO(kevinb): decide best return type
  public static List<Throwable> getCausalChain(Throwable throwable) {
    checkNotNull(throwable);
    List<Throwable> causes = new ArrayList<>(4);
    causes.add(throwable);

    // Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
    // the slower pointer, then there's a loop.
    Throwable slowPointer = throwable;
    boolean advanceSlowPointer = false;

    Throwable cause;
    while ((cause = throwable.getCause()) != null) {
      throwable = cause;
      causes.add(throwable);

      if (throwable == slowPointer) {
        throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
      }
      if (advanceSlowPointer) {
        slowPointer = slowPointer.getCause();
      }
      advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
    }
    return Collections.unmodifiableList(causes);
  }

  /**
   * Returns {@code throwable}'s cause, cast to {@code expectedCauseType}.
   *
   *
Prefer this method instead of manually casting an exception's cause. For example, {@code
   * (IOException) e.getCause()} throws a {@link ClassCastException} that discards the original
   * exception {@code e} if the cause is not an {@link IOException}, but {@code
   * Throwables.getCauseAs(e, IOException.class)} keeps {@code e} as the {@link
   * ClassCastException}'s cause.
   *
   * @throws ClassCastException if the cause cannot be cast to the expected type. The {@code
   *     ClassCastException}'s cause is {@code throwable}.
   * @since 22.0
   */
  @Beta
  @GwtIncompatible // Class.cast(Object)
  public static <X extends Throwable> X getCauseAs(
      Throwable throwable, Class<X> expectedCauseType) {
    try {
      return expectedCauseType.cast(throwable.getCause());
    } catch (ClassCastException e) {
      e.initCause(throwable);
      throw e;
    }
  }

  /**
   * Returns a string containing the result of {@link Throwable#toString() toString()}, followed by
   * the full, recursive stack trace of {@code throwable}. Note that you probably should not be
   * parsing the resulting string; if you need programmatic access to the stack frames, you can call
   * {@link Throwable#getStackTrace()}.
   */
  @GwtIncompatible // java.io.PrintWriter, java.io.StringWriter
  public static String getStackTraceAsString(Throwable throwable) {
    StringWriter stringWriter = new StringWriter();
    throwable.printStackTrace(new PrintWriter(stringWriter));
    return stringWriter.toString();
  }

  /**
   * Returns the stack trace of {@code throwable}, possibly providing slower iteration over the full
   * trace but faster iteration over parts of the trace. Here, "slower" and "faster" are defined in
   * comparison to the normal way to access the stack trace, {@link Throwable#getStackTrace()
   * throwable.getStackTrace()}. Note, however, that this method's special implementation is not
   * available for all platforms and configurations. If that implementation is unavailable, this
   * method falls back to {@code getStackTrace}. Callers that require the special implementation can
   * check its availability with {@link #lazyStackTraceIsLazy()}.
   *
   *
The expected (but not guaranteed) performance of the special implementation differs from
   * {@code getStackTrace} in one main way: The {@code lazyStackTrace} call itself returns quickly
   * by delaying the per-stack-frame work until each element is accessed. Roughly speaking:
   *
   *

   *
{@code getStackTrace} takes {@code stackSize} time to return but then negligible time to
   *       retrieve each element of the returned list.
   *
{@code lazyStackTrace} takes negligible time to return but then {@code 1/stackSize} time
   *       to retrieve each element of the returned list (probably slightly more than {@code
   *       1/stackSize}).
   *

   *
   *
Note: The special implementation does not respect calls to {@link Throwable#setStackTrace
   * throwable.setStackTrace}. Instead, it always reflects the original stack trace from the
   * exception's creation.
   *
   * @since 19.0
   */
  // TODO(cpovirk): Say something about the possibility that List access could fail at runtime?
  @Beta
  @GwtIncompatible // lazyStackTraceIsLazy, jlaStackTrace
  // TODO(cpovirk): Consider making this available under GWT (slow implementation only).
  public static List<StackTraceElement> lazyStackTrace(Throwable throwable) {
    return lazyStackTraceIsLazy()
        ? jlaStackTrace(throwable)
        : unmodifiableList(asList(throwable.getStackTrace()));
  }

  /**
   * Returns whether {@link #lazyStackTrace} will use the special implementation described in its
   * documentation.
   *
   * @since 19.0
   */
  @Beta
  @GwtIncompatible // getStackTraceElementMethod
  public static boolean lazyStackTraceIsLazy() {
    return getStackTraceElementMethod != null && getStackTraceDepthMethod != null;
  }

  @GwtIncompatible // invokeAccessibleNonThrowingMethod
  private static List<StackTraceElement> jlaStackTrace(final Throwable t) {
    checkNotNull(t);
    /*
     * TODO(cpovirk): Consider optimizing iterator() to catch IOOBE instead of doing bounds checks.
     *
     * TODO(cpovirk): Consider the UnsignedBytes pattern if it performs faster and doesn't cause
     * AOSP grief.
     */
    return new AbstractList<StackTraceElement>() {
      @Override
      public StackTraceElement get(int n) {
        return (StackTraceElement)
            invokeAccessibleNonThrowingMethod(getStackTraceElementMethod, jla, t, n);
      }

      @Override
      public int size() {
        return (Integer) invokeAccessibleNonThrowingMethod(getStackTraceDepthMethod, jla, t);
      }
    };
  }

  @GwtIncompatible // java.lang.reflect
  private static Object invokeAccessibleNonThrowingMethod(
      Method method, Object receiver, Object... params) {
    try {
      return method.invoke(receiver, params);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
      throw propagate(e.getCause());
    }
  }

  /** JavaLangAccess class name to load using reflection */
  @GwtIncompatible // not used by GWT emulation
  private static final String JAVA_LANG_ACCESS_CLASSNAME = "sun.misc.JavaLangAccess";

  /** SharedSecrets class name to load using reflection */
  @GwtIncompatible // not used by GWT emulation
  @VisibleForTesting
  static final String SHARED_SECRETS_CLASSNAME = "sun.misc.SharedSecrets";

  /** Access to some fancy internal JVM internals. */
  @GwtIncompatible // java.lang.reflect
  private static final @Nullable Object jla = getJLA();

  /**
   * The "getStackTraceElementMethod" method, only available on some JDKs so we use reflection to
   * find it when available. When this is null, use the slow way.
   */
  @GwtIncompatible // java.lang.reflect
  private static final @Nullable Method getStackTraceElementMethod =
      (jla == null) ? null : getGetMethod();

  /**
   * The "getStackTraceDepth" method, only available on some JDKs so we use reflection to find it
   * when available. When this is null, use the slow way.
   */
  @GwtIncompatible // java.lang.reflect
  private static final @Nullable Method getStackTraceDepthMethod =
      (jla == null) ? null : getSizeMethod();

  /**
   * Returns the JavaLangAccess class that is present in all Sun JDKs. It is not allowed in
   * AppEngine, and not present in non-Sun JDKs.
   */
  @GwtIncompatible // java.lang.reflect
  private static @Nullable Object getJLA() {
    try {
      /*
       * We load sun.misc.* classes using reflection since Android doesn't support these classes and
       * would result in compilation failure if we directly refer to these classes.
       */
      Class<?> sharedSecrets = Class.forName(SHARED_SECRETS_CLASSNAME, false, null);
      Method langAccess = sharedSecrets.getMethod("getJavaLangAccess");
      return langAccess.invoke(null);
    } catch (ThreadDeath death) {
      throw death;
    } catch (Throwable t) {
      /*
       * This is not one of AppEngine's allowed classes, so even in Sun JDKs, this can fail with
       * a NoClassDefFoundError. Other apps might deny access to sun.misc packages.
       */
      return null;
    }
  }

  /**
   * Returns the Method that can be used to resolve an individual StackTraceElement, or null if that
   * method cannot be found (it is only to be found in fairly recent JDKs).
   */
  @GwtIncompatible // java.lang.reflect
  private static @Nullable Method getGetMethod() {
    return getJlaMethod("getStackTraceElement", Throwable.class, int.class);
  }

  /**
   * Returns the Method that can be used to return the size of a stack, or null if that method
   * cannot be found (it is only to be found in fairly recent JDKs). Tries to test method {@link
   * sun.misc.JavaLangAccess#getStackTraceDepth(Throwable)} getStackTraceDepth} prior to return it
   * (might fail some JDKs).
   *
   *
See Throwables#lazyStackTrace throws
   * UnsupportedOperationException.
   */
  @GwtIncompatible // java.lang.reflect
  private static @Nullable Method getSizeMethod() {
    try {
      Method getStackTraceDepth = getJlaMethod("getStackTraceDepth", Throwable.class);
      if (getStackTraceDepth == null) {
        return null;
      }
      getStackTraceDepth.invoke(getJLA(), new Throwable());
      return getStackTraceDepth;
    } catch (UnsupportedOperationException | IllegalAccessException | InvocationTargetException e) {
      return null;
    }
  }

  @GwtIncompatible // java.lang.reflect
  private static @Nullable Method getJlaMethod(String name, Class<?>... parameterTypes)
      throws ThreadDeath {
    try {
      return Class.forName(JAVA_LANG_ACCESS_CLASSNAME, false, null).getMethod(name, parameterTypes);
    } catch (ThreadDeath death) {
      throw death;
    } catch (Throwable t) {
      /*
       * Either the JavaLangAccess class itself is not found, or the method is not supported on the
       * JVM.
       */
      return null;
    }
  }
}


/*
 * Copyright (C) 2012 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.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.math.DoubleUtils.ensureNonNegative;
import static com.google.common.math.StatsAccumulator.calculateNewMeanNonFinite;
import static com.google.common.primitives.Doubles.isFinite;
import static java.lang.Double.NaN;
import static java.lang.Double.doubleToLongBits;
import static java.lang.Double.isNaN;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Iterator;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * A bundle of statistical summary values -- sum, count, mean/average, min and max, and several
 * forms of variance -- that were computed from a single set of zero or more floating-point values.
 *
 *
There are two ways to obtain a {@code Stats} instance:
 *
 *

 *
If all the values you want to summarize are already known, use the appropriate {@code
 *       Stats.of} factory method below. Primitive arrays, iterables and iterators of any kind of
 *       {@code Number}, and primitive varargs are supported.
 *
Or, to avoid storing up all the data first, create a {@link StatsAccumulator} instance,
 *       feed values to it as you get them, then call {@link StatsAccumulator#snapshot}.
 *

 *
 *
Static convenience methods called {@code meanOf} are also provided for users who wish to
 * calculate only the mean.
 *
 *
Java 8 users: If you are not using any of the variance statistics, you may wish to use
 * built-in JDK libraries instead of this class.
 *
 * @author Pete Gillin
 * @author Kevin Bourrillion
 * @since 20.0
 */
@Beta
@GwtIncompatible
public final class Stats implements Serializable {

  private final long count;
  private final double mean;
  private final double sumOfSquaresOfDeltas;
  private final double min;
  private final double max;

  /**
   * Internal constructor. Users should use {@link #of} or {@link StatsAccumulator#snapshot}.
   *
   *
To ensure that the created instance obeys its contract, the parameters should satisfy the
   * following constraints. This is the callers responsibility and is not enforced here.
   *
   *

   *
If {@code count} is 0, {@code mean} may have any finite value (its only usage will be to
   *       get multiplied by 0 to calculate the sum), and the other parameters may have any values
   *       (they will not be used).
   *
If {@code count} is 1, {@code sumOfSquaresOfDeltas} must be exactly 0.0 or {@link
   *       Double#NaN}.
   *

   */
  Stats(long count, double mean, double sumOfSquaresOfDeltas, double min, double max) {
    this.count = count;
    this.mean = mean;
    this.sumOfSquaresOfDeltas = sumOfSquaresOfDeltas;
    this.min = min;
    this.max = max;
  }

  /**
   * Returns statistics over a dataset containing the given values.
   *
   * @param values a series of values, which will be converted to {@code double} values (this may
   *     cause loss of precision)
   */
  public static Stats of(Iterable<? extends Number> values) {
    StatsAccumulator accumulator = new StatsAccumulator();
    accumulator.addAll(values);
    return accumulator.snapshot();
  }

  /**
   * Returns statistics over a dataset containing the given values.
   *
   * @param values a series of values, which will be converted to {@code double} values (this may
   *     cause loss of precision)
   */
  public static Stats of(Iterator<? extends Number> values) {
    StatsAccumulator accumulator = new StatsAccumulator();
    accumulator.addAll(values);
    return accumulator.snapshot();
  }

  /**
   * Returns statistics over a dataset containing the given values.
   *
   * @param values a series of values
   */
  public static Stats of(double... values) {
    StatsAccumulator acummulator = new StatsAccumulator();
    acummulator.addAll(values);
    return acummulator.snapshot();
  }

  /**
   * Returns statistics over a dataset containing the given values.
   *
   * @param values a series of values
   */
  public static Stats of(int... values) {
    StatsAccumulator acummulator = new StatsAccumulator();
    acummulator.addAll(values);
    return acummulator.snapshot();
  }

  /**
   * Returns statistics over a dataset containing the given values.
   *
   * @param values a 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))
   */
  public static Stats of(long... values) {
    StatsAccumulator acummulator = new StatsAccumulator();
    acummulator.addAll(values);
    return acummulator.snapshot();
  }

  /** Returns the number of values. */
  public long count() {
    return count;
  }

  /**
   * Returns the arithmetic mean of the
   * values. The count must be non-zero.
   *
   *
If these values are a sample drawn from a population, this is also an unbiased estimator of
   * the arithmetic mean of the population.
   *
   *
Non-finite values

   *
   *
If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
   * contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the
   * result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
   * only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}.
   * If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link
   * Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}.
   *
   *
If you only want to calculate the mean, use {#meanOf} instead of creating a {@link Stats}
   * instance.
   *
   * @throws IllegalStateException if the dataset is empty
   */
  public double mean() {
    checkState(count != 0);
    return mean;
  }

  /**
   * Returns the sum of the values.
   *
   *
Non-finite values

   *
   *
If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
   * contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the
   * result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
   * only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}.
   * If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link
   * Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}.
   */
  public double sum() {
    return mean * count;
  }

  /**
   * Returns the population
   * variance of the values. The count must be non-zero.
   *
   *
This is guaranteed to return zero if the dataset contains only exactly one finite value. It
   * is not guaranteed to return zero when the dataset consists of the same value multiple times,
   * due to numerical errors. However, it is guaranteed never to return a negative result.
   *
   *
Non-finite values

   *
   *
If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
   *
   * @throws IllegalStateException if the dataset is empty
   */
  public double populationVariance() {
    checkState(count > 0);
    if (isNaN(sumOfSquaresOfDeltas)) {
      return NaN;
    }
    if (count == 1) {
      return 0.0;
    }
    return ensureNonNegative(sumOfSquaresOfDeltas) / count();
  }

  /**
   * Returns the
   * population standard deviation of the values. The count must be non-zero.
   *
   *
This is guaranteed to return zero if the dataset contains only exactly one finite value. It
   * is not guaranteed to return zero when the dataset consists of the same value multiple times,
   * due to numerical errors. However, it is guaranteed never to return a negative result.
   *
   *
Non-finite values

   *
   *
If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
   *
   * @throws IllegalStateException if the dataset is empty
   */
  public double populationStandardDeviation() {
    return Math.sqrt(populationVariance());
  }

  /**
   * Returns the unbiased sample
   * variance of the values. If this dataset is a sample drawn from a population, this is an
   * unbiased estimator of the population variance of the population. The count must be greater than
   * one.
   *
   *
This is not guaranteed to return zero when the dataset consists of the same value multiple
   * times, due to numerical errors. However, it is guaranteed never to return a negative result.
   *
   *
Non-finite values

   *
   *
If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
   *
   * @throws IllegalStateException if the dataset is empty or contains a single value
   */
  public double sampleVariance() {
    checkState(count > 1);
    if (isNaN(sumOfSquaresOfDeltas)) {
      return NaN;
    }
    return ensureNonNegative(sumOfSquaresOfDeltas) / (count - 1);
  }

  /**
   * Returns the
   * corrected sample standard deviation of the values. If this dataset is a sample drawn from a
   * population, this is an estimator of the population standard deviation of the population which
   * is less biased than {@link #populationStandardDeviation()} (the unbiased estimator depends on
   * the distribution). The count must be greater than one.
   *
   *
This is not guaranteed to return zero when the dataset consists of the same value multiple
   * times, due to numerical errors. However, it is guaranteed never to return a negative result.
   *
   *
Non-finite values

   *
   *
If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link
   * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}.
   *
   * @throws IllegalStateException if the dataset is empty or contains a single value
   */
  public double sampleStandardDeviation() {
    return Math.sqrt(sampleVariance());
  }

  /**
   * Returns the lowest value in the dataset. The count must be non-zero.
   *
   *
Non-finite values

   *
   *
If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
   * contains {@link Double#NEGATIVE_INFINITY} and not {@link Double#NaN} then the result is {@link
   * Double#NEGATIVE_INFINITY}. If it contains {@link Double#POSITIVE_INFINITY} and finite values
   * only then the result is the lowest finite value. If it contains {@link
   * Double#POSITIVE_INFINITY} only then the result is {@link Double#POSITIVE_INFINITY}.
   *
   * @throws IllegalStateException if the dataset is empty
   */
  public double min() {
    checkState(count != 0);
    return min;
  }

  /**
   * Returns the highest value in the dataset. The count must be non-zero.
   *
   *
Non-finite values

   *
   *
If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it
   * contains {@link Double#POSITIVE_INFINITY} and not {@link Double#NaN} then the result is {@link
   * Double#POSITIVE_INFINITY}. If it contains {@link Double#NEGATIVE_INFINITY} and finite values
   * only then the result is the highest finite value. If it contains {@link
   * Double#NEGATIVE_INFINITY} only then the result is {@link Double#NEGATIVE_INFINITY}.
   *
   * @throws IllegalStateException if the dataset is empty
   */
  public double max() {
    checkState(count != 0);
    return max;
  }

  /**
   * {@inheritDoc}
   *
   *
Note: This tests exact equality of the calculated statistics, including the floating
   * point values. Two instances are guaranteed to be considered equal if one is copied from the
   * other using {@code second = new StatsAccumulator().addAll(first).snapshot()}, if both were
   * obtained by calling {@code snapshot()} on the same {@link StatsAccumulator} without adding any
   * values in between the two calls, or if one is obtained from the other after round-tripping
   * through java serialization. However, floating point rounding errors mean that it may be false
   * for some instances where the statistics are mathematically equal, including instances
   * constructed from the same values in a different order... or (in the general case) even in the
   * same order. (It is guaranteed to return true for instances constructed from the same values in
   * the same order if {@code strictfp} is in effect, or if the system architecture guarantees
   * {@code strictfp}-like semantics.)
   */
  @Override
  public boolean equals(@NullableDecl Object obj) {
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    Stats other = (Stats) obj;
    return (count == other.count)
        && (doubleToLongBits(mean) == doubleToLongBits(other.mean))
        && (doubleToLongBits(sumOfSquaresOfDeltas) == doubleToLongBits(other.sumOfSquaresOfDeltas))
        && (doubleToLongBits(min) == doubleToLongBits(other.min))
        && (doubleToLongBits(max) == doubleToLongBits(other.max));
  }

  /**
   * {@inheritDoc}
   *
   *
Note: This hash code is consistent with exact equality of the calculated statistics,
   * including the floating point values. See the note on {@link #equals} for details.
   */
  @Override
  public int hashCode() {
    return Objects.hashCode(count, mean, sumOfSquaresOfDeltas, min, max);
  }

  @Override
  public String toString() {
    if (count() > 0) {
      return MoreObjects.toStringHelper(this)
          .add("count", count)
          .add("mean", mean)
          .add("populationStandardDeviation", populationStandardDeviation())
          .add("min", min)
          .add("max", max)
          .toString();
    } else {
      return MoreObjects.toStringHelper(this).add("count", count).toString();
    }
  }

  double sumOfSquaresOfDeltas() {
    return sumOfSquaresOfDeltas;
  }

  /**
   * Returns the arithmetic mean of the
   * values. The count must be non-zero.
   *
   *
The definition of the mean is the same as {@link Stats#mean}.
   *
   * @param values a series of values, which will be converted to {@code double} values (this may
   *     cause loss of precision)
   * @throws IllegalArgumentException if the dataset is empty
   */
  public static double meanOf(Iterable<? extends Number> values) {
    return meanOf(values.iterator());
  }

  /**
   * Returns the arithmetic mean of the
   * values. The count must be non-zero.
   *
   *
The definition of the mean is the same as {@link Stats#mean}.
   *
   * @param values a series of values, which will be converted to {@code double} values (this may
   *     cause loss of precision)
   * @throws IllegalArgumentException if the dataset is empty
   */
  public static double meanOf(Iterator<? extends Number> values) {
    checkArgument(values.hasNext());
    long count = 1;
    double mean = values.next().doubleValue();
    while (values.hasNext()) {
      double value = values.next().doubleValue();
      count++;
      if (isFinite(value) && isFinite(mean)) {
        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
        mean += (value - mean) / count;
      } else {
        mean = calculateNewMeanNonFinite(mean, value);
      }
    }
    return mean;
  }

  /**
   * Returns the arithmetic mean of the
   * values. The count must be non-zero.
   *
   *
The definition of the mean is the same as {@link Stats#mean}.
   *
   * @param values a series of values
   * @throws IllegalArgumentException if the dataset is empty
   */
  public static double meanOf(double... values) {
    checkArgument(values.length > 0);
    double mean = values[0];
    for (int index = 1; index < values.length; index++) {
      double value = values[index];
      if (isFinite(value) && isFinite(mean)) {
        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
        mean += (value - mean) / (index + 1);
      } else {
        mean = calculateNewMeanNonFinite(mean, value);
      }
    }
    return mean;
  }

  /**
   * Returns the arithmetic mean of the
   * values. The count must be non-zero.
   *
   *
The definition of the mean is the same as {@link Stats#mean}.
   *
   * @param values a series of values
   * @throws IllegalArgumentException if the dataset is empty
   */
  public static double meanOf(int... values) {
    checkArgument(values.length > 0);
    double mean = values[0];
    for (int index = 1; index < values.length; index++) {
      double value = values[index];
      if (isFinite(value) && isFinite(mean)) {
        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
        mean += (value - mean) / (index + 1);
      } else {
        mean = calculateNewMeanNonFinite(mean, value);
      }
    }
    return mean;
  }

  /**
   * Returns the arithmetic mean of the
   * values. The count must be non-zero.
   *
   *
The definition of the mean is the same as {@link Stats#mean}.
   *
   * @param values a 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 the dataset is empty
   */
  public static double meanOf(long... values) {
    checkArgument(values.length > 0);
    double mean = values[0];
    for (int index = 1; index < values.length; index++) {
      double value = values[index];
      if (isFinite(value) && isFinite(mean)) {
        // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15)
        mean += (value - mean) / (index + 1);
      } else {
        mean = calculateNewMeanNonFinite(mean, value);
      }
    }
    return mean;
  }

  // Serialization helpers

  /** The size of byte array representation in bytes. */
  static final int BYTES = (Long.SIZE + Double.SIZE * 4) / Byte.SIZE;

  /**
   * Gets a byte array representation of this instance.
   *
   *
Note: No guarantees are made regarding stability of the representation between
   * versions.
   */
  public byte[] toByteArray() {
    ByteBuffer buff = ByteBuffer.allocate(BYTES).order(ByteOrder.LITTLE_ENDIAN);
    writeTo(buff);
    return buff.array();
  }

  /**
   * Writes to the given {@link ByteBuffer} a byte representation of this instance.
   *
   *
Note: No guarantees are made regarding stability of the representation between
   * versions.
   *
   * @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as
   *     {@link ByteOrder#LITTLE_ENDIAN}, to which a BYTES-long byte representation of this instance
   *     is written. In the process increases the position of {@link ByteBuffer} by BYTES.
   */
  void writeTo(ByteBuffer buffer) {
    checkNotNull(buffer);
    checkArgument(
        buffer.remaining() >= BYTES,
        "Expected at least Stats.BYTES = %s remaining , got %s",
        BYTES,
        buffer.remaining());
    buffer
        .putLong(count)
        .putDouble(mean)
        .putDouble(sumOfSquaresOfDeltas)
        .putDouble(min)
        .putDouble(max);
  }

  /**
   * Creates a Stats instance from the given byte representation which was obtained by {@link
   * #toByteArray}.
   *
   *
Note: No guarantees are made regarding stability of the representation between
   * versions.
   */
  public static Stats fromByteArray(byte[] byteArray) {
    checkNotNull(byteArray);
    checkArgument(
        byteArray.length == BYTES,
        "Expected Stats.BYTES = %s remaining , got %s",
        BYTES,
        byteArray.length);
    return readFrom(ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN));
  }

  /**
   * Creates a Stats instance from the byte representation read from the given {@link ByteBuffer}.
   *
   *
Note: No guarantees are made regarding stability of the representation between
   * versions.
   *
   * @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as
   *     {@link ByteOrder#LITTLE_ENDIAN}, from which a BYTES-long byte representation of this
   *     instance is read. In the process increases the position of {@link ByteBuffer} by BYTES.
   */
  static Stats readFrom(ByteBuffer buffer) {
    checkNotNull(buffer);
    checkArgument(
        buffer.remaining() >= BYTES,
        "Expected at least Stats.BYTES = %s remaining , got %s",
        BYTES,
        buffer.remaining());
    return new Stats(
        buffer.getLong(),
        buffer.getDouble(),
        buffer.getDouble(),
        buffer.getDouble(),
        buffer.getDouble());
  }

  private static final long serialVersionUID = 0;
}


/*
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

/*
 * Source:
 * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDoubleArray.java?revision=1.5
 * (Modified to adapt to guava coding conventions and
 * to use AtomicLongArray instead of sun.misc.Unsafe)
 */

package com.google.common.util.concurrent;

import static java.lang.Double.doubleToRawLongBits;
import static java.lang.Double.longBitsToDouble;

import com.google.common.annotations.GwtIncompatible;
import com.google.common.primitives.ImmutableLongArray;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.concurrent.atomic.AtomicLongArray;

/**
 * A {@code double} array in which elements may be updated atomically. See the {@link
 * java.util.concurrent.atomic} package specification for description of the properties of atomic
 * variables.
 *
 *
This class compares primitive {@code double} values in methods such as
 * {@link #compareAndSet} by comparing their bitwise representation using {@link
 * Double#doubleToRawLongBits}, which differs from both the primitive double {@code ==} operator and
 * from {@link Double#equals}, as if implemented by:
 *
 *
{@code
 * static boolean bitEquals(double x, double y) {
 *   long xBits = Double.doubleToRawLongBits(x);
 *   long yBits = Double.doubleToRawLongBits(y);
 *   return xBits == yBits;
 * }
 * }

 *
 * @author Doug Lea
 * @author Martin Buchholz
 * @since 11.0
 */
@GwtIncompatible
public class AtomicDoubleArray implements java.io.Serializable {
  private static final long serialVersionUID = 0L;

  // Making this non-final is the lesser evil according to Effective
  // Java 2nd Edition Item 76: Write readObject methods defensively.
  private transient AtomicLongArray longs;

  /**
   * Creates a new {@code AtomicDoubleArray} of the given length, with all elements initially zero.
   *
   * @param length the length of the array
   */
  public AtomicDoubleArray(int length) {
    this.longs = new AtomicLongArray(length);
  }

  /**
   * Creates a new {@code AtomicDoubleArray} with the same length as, and all elements copied from,
   * the given array.
   *
   * @param array the array to copy elements from
   * @throws NullPointerException if array is null
   */
  public AtomicDoubleArray(double[] array) {
    final int len = array.length;
    long[] longArray = new long[len];
    for (int i = 0; i < len; i++) {
      longArray[i] = doubleToRawLongBits(array[i]);
    }
    this.longs = new AtomicLongArray(longArray);
  }

  /**
   * Returns the length of the array.
   *
   * @return the length of the array
   */
  public final int length() {
    return longs.length();
  }

  /**
   * Gets the current value at position {@code i}.
   *
   * @param i the index
   * @return the current value
   */
  public final double get(int i) {
    return longBitsToDouble(longs.get(i));
  }

  /**
   * Sets the element at position {@code i} to the given value.
   *
   * @param i the index
   * @param newValue the new value
   */
  public final void set(int i, double newValue) {
    long next = doubleToRawLongBits(newValue);
    longs.set(i, next);
  }

  /**
   * Eventually sets the element at position {@code i} to the given value.
   *
   * @param i the index
   * @param newValue the new value
   */
  public final void lazySet(int i, double newValue) {
    long next = doubleToRawLongBits(newValue);
    longs.lazySet(i, next);
  }

  /**
   * Atomically sets the element at position {@code i} to the given value and returns the old value.
   *
   * @param i the index
   * @param newValue the new value
   * @return the previous value
   */
  public final double getAndSet(int i, double newValue) {
    long next = doubleToRawLongBits(newValue);
    return longBitsToDouble(longs.getAndSet(i, next));
  }

  /**
   * Atomically sets the element at position {@code i} to the given updated value if the current
   * value is bitwise equal to the expected value.
   *
   * @param i the index
   * @param expect the expected value
   * @param update the new value
   * @return true if successful. False return indicates that the actual value was not equal to the
   *     expected value.
   */
  public final boolean compareAndSet(int i, double expect, double update) {
    return longs.compareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update));
  }

  /**
   * Atomically sets the element at position {@code i} to the given updated value if the current
   * value is bitwise equal to the expected value.
   *
   *
May
   * fail spuriously and does not provide ordering guarantees, so is only rarely an appropriate
   * alternative to {@code compareAndSet}.
   *
   * @param i the index
   * @param expect the expected value
   * @param update the new value
   * @return true if successful
   */
  public final boolean weakCompareAndSet(int i, double expect, double update) {
    return longs.weakCompareAndSet(i, doubleToRawLongBits(expect), doubleToRawLongBits(update));
  }

  /**
   * Atomically adds the given value to the element at index {@code i}.
   *
   * @param i the index
   * @param delta the value to add
   * @return the previous value
   */
  @CanIgnoreReturnValue
  public final double getAndAdd(int i, double delta) {
    while (true) {
      long current = longs.get(i);
      double currentVal = longBitsToDouble(current);
      double nextVal = currentVal + delta;
      long next = doubleToRawLongBits(nextVal);
      if (longs.compareAndSet(i, current, next)) {
        return currentVal;
      }
    }
  }

  /**
   * Atomically adds the given value to the element at index {@code i}.
   *
   * @param i the index
   * @param delta the value to add
   * @return the updated value
   */
  @CanIgnoreReturnValue
  public double addAndGet(int i, double delta) {
    while (true) {
      long current = longs.get(i);
      double currentVal = longBitsToDouble(current);
      double nextVal = currentVal + delta;
      long next = doubleToRawLongBits(nextVal);
      if (longs.compareAndSet(i, current, next)) {
        return nextVal;
      }
    }
  }

  /**
   * Returns the String representation of the current values of array.
   *
   * @return the String representation of the current values of array
   */
  @Override
  public String toString() {
    int iMax = length() - 1;
    if (iMax == -1) {
      return "[]";
    }

    // Double.toString(Math.PI).length() == 17
    StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
    b.append('[');
    for (int i = 0; ; i++) {
      b.append(longBitsToDouble(longs.get(i)));
      if (i == iMax) {
        return b.append(']').toString();
      }
      b.append(',').append(' ');
    }
  }

  /**
   * Saves the state to a stream (that is, serializes it).
   *
   * @serialData The length of the array is emitted (int), followed by all of its elements (each a
   *     {@code double}) in the proper order.
   */
  private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
    s.defaultWriteObject();

    // Write out array length
    int length = length();
    s.writeInt(length);

    // Write out all elements in the proper order.
    for (int i = 0; i < length; i++) {
      s.writeDouble(get(i));
    }
  }

  /** Reconstitutes the instance from a stream (that is, deserializes it). */
  private void readObject(java.io.ObjectInputStream s)
      throws java.io.IOException, ClassNotFoundException {
    s.defaultReadObject();

    int length = s.readInt();
    ImmutableLongArray.Builder builder = ImmutableLongArray.builder();
    for (int i = 0; i < length; i++) {
      builder.add(doubleToRawLongBits(s.readDouble()));
    }
    this.longs = new AtomicLongArray(builder.build().toArray());
  }
}


/*
 * 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 static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.graph.GraphConstants.NOT_AVAILABLE_ON_UNDIRECTED;

import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import com.google.common.collect.Iterators;
import com.google.common.collect.UnmodifiableIterator;
import com.google.errorprone.annotations.Immutable;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * An immutable pair representing the two endpoints of an edge in a graph. The {@link EndpointPair}
 * of a directed edge is an ordered pair of nodes ({@link #source()} and {@link #target()}). The
 * {@link EndpointPair} of an undirected edge is an unordered pair of nodes ({@link #nodeU()} and
 * {@link #nodeV()}).
 *
 * <p>The edge is a self-loop if, and only if, the two endpoints are equal.
 *
 * @author James Sexton
 * @since 20.0
 */
@Beta
@Immutable(containerOf = {"N"})
public abstract class EndpointPair<N> implements Iterable<N> {
  private final N nodeU;
  private final N nodeV;

  private EndpointPair(N nodeU, N nodeV) {
    this.nodeU = checkNotNull(nodeU);
    this.nodeV = checkNotNull(nodeV);
  }

  /** Returns an {@link EndpointPair} representing the endpoints of a directed edge. */
  public static <N> EndpointPair<N> ordered(N source, N target) {
    return new Ordered<N>(source, target);
  }

  /** Returns an {@link EndpointPair} representing the endpoints of an undirected edge. */
  public static <N> EndpointPair<N> unordered(N nodeU, N nodeV) {
    // Swap nodes on purpose to prevent callers from relying on the "ordering" of an unordered pair.
    return new Unordered<N>(nodeV, nodeU);
  }

  /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code graph}. */
  static <N> EndpointPair<N> of(Graph<?> graph, N nodeU, N nodeV) {
    return graph.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV);
  }

  /** Returns an {@link EndpointPair} representing the endpoints of an edge in {@code network}. */
  static <N> EndpointPair<N> of(Network<?, ?> network, N nodeU, N nodeV) {
    return network.isDirected() ? ordered(nodeU, nodeV) : unordered(nodeU, nodeV);
  }

  /**
   * If this {@link EndpointPair} {@link #isOrdered()}, returns the node which is the source.
   *
   * @throws UnsupportedOperationException if this {@link EndpointPair} is not ordered
   */
  public abstract N source();

  /**
   * If this {@link EndpointPair} {@link #isOrdered()}, returns the node which is the target.
   *
   * @throws UnsupportedOperationException if this {@link EndpointPair} is not ordered
   */
  public abstract N target();

  /**
   * If this {@link EndpointPair} {@link #isOrdered()} returns the {@link #source()}; otherwise,
   * returns an arbitrary (but consistent) endpoint of the origin edge.
   */
  public final N nodeU() {
    return nodeU;
  }

  /**
   * Returns the node {@link #adjacentNode(Object) adjacent} to {@link #nodeU()} along the origin
   * edge. If this {@link EndpointPair} {@link #isOrdered()}, this is equal to {@link #target()}.
   */
  public final N nodeV() {
    return nodeV;
  }

  /**
   * Returns the node that is adjacent to {@code node} along the origin edge.
   *
   * @throws IllegalArgumentException if this {@link EndpointPair} does not contain {@code node}
   */
  public final N adjacentNode(Object node) {
    if (node.equals(nodeU)) {
      return nodeV;
    } else if (node.equals(nodeV)) {
      return nodeU;
    } else {
      throw new IllegalArgumentException("EndpointPair " + this + " does not contain node " + node);
    }
  }

  /**
   * Returns {@code true} if this {@link EndpointPair} is an ordered pair (i.e. represents the
   * endpoints of a directed edge).
   */
  public abstract boolean isOrdered();

  /** Iterates in the order {@link #nodeU()}, {@link #nodeV()}. */
  @Override
  public final UnmodifiableIterator<N> iterator() {
    return Iterators.forArray(nodeU, nodeV);
  }

  /**
   * Two ordered {@link EndpointPair}s are equal if their {@link #source()} and {@link #target()}
   * are equal. Two unordered {@link EndpointPair}s are equal if they contain the same nodes. An
   * ordered {@link EndpointPair} is never equal to an unordered {@link EndpointPair}.
   */
  @Override
  public abstract boolean equals(@NullableDecl Object obj);

  /**
   * The hashcode of an ordered {@link EndpointPair} is equal to {@code Objects.hashCode(source(),
   * target())}. The hashcode of an unordered {@link EndpointPair} is equal to {@code
   * nodeU().hashCode() + nodeV().hashCode()}.
   */
  @Override
  public abstract int hashCode();

  private static final class Ordered<N> extends EndpointPair<N> {
    private Ordered(N source, N target) {
      super(source, target);
    }

    @Override
    public N source() {
      return nodeU();
    }

    @Override
    public N target() {
      return nodeV();
    }

    @Override
    public boolean isOrdered() {
      return true;
    }

    @Override
    public boolean equals(@NullableDecl Object obj) {
      if (obj == this) {
        return true;
      }
      if (!(obj instanceof EndpointPair)) {
        return false;
      }

      EndpointPair<?> other = (EndpointPair<?>) obj;
      if (isOrdered() != other.isOrdered()) {
        return false;
      }

      return source().equals(other.source()) && target().equals(other.target());
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(source(), target());
    }

    @Override
    public String toString() {
      return "<" + source() + " -> " + target() + ">";
    }
  }

  private static final class Unordered<N> extends EndpointPair<N> {
    private Unordered(N nodeU, N nodeV) {
      super(nodeU, nodeV);
    }

    @Override
    public N source() {
      throw new UnsupportedOperationException(NOT_AVAILABLE_ON_UNDIRECTED);
    }

    @Override
    public N target() {
      throw new UnsupportedOperationException(NOT_AVAILABLE_ON_UNDIRECTED);
    }

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

    @Override
    public boolean equals(@NullableDecl Object obj) {
      if (obj == this) {
        return true;
      }
      if (!(obj instanceof EndpointPair)) {
        return false;
      }

      EndpointPair<?> other = (EndpointPair<?>) obj;
      if (isOrdered() != other.isOrdered()) {
        return false;
      }

      // Equivalent to the following simple implementation:
      // boolean condition1 = nodeU().equals(other.nodeU()) && nodeV().equals(other.nodeV());
      // boolean condition2 = nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU());
      // return condition1 || condition2;
      if (nodeU().equals(other.nodeU())) { // check condition1
        // Here's the tricky bit. We don't have to explicitly check for condition2 in this case.
        // Why? The second half of condition2 requires that nodeV equals other.nodeU.
        // We already know that nodeU equals other.nodeU. Combined with the earlier statement,
        // and the transitive property of equality, this implies that nodeU equals nodeV.
        // If nodeU equals nodeV, condition1 == condition2, so checking condition1 is sufficient.
        return nodeV().equals(other.nodeV());
      }
      return nodeU().equals(other.nodeV()) && nodeV().equals(other.nodeU()); // check condition2
    }

    @Override
    public int hashCode() {
      return nodeU().hashCode() + nodeV().hashCode();
    }

    @Override
    public String toString() {
      return "[" + nodeU() + ", " + nodeV() + "]";
    }
  }
}


/*
 * 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 static com.google.common.base.Preconditions.checkState;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.j2objc.annotations.J2ObjCIncompatible;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * An object that measures elapsed time in nanoseconds. It is useful to measure elapsed time using
 * this class instead of direct calls to {@link System#nanoTime} for a few reasons:
 *
 *

 *
An alternate time source can be substituted, for testing or performance reasons.
 *
As documented by {@code nanoTime}, the value returned has no absolute meaning, and can only
 *       be interpreted as relative to another timestamp returned by {@code nanoTime} at a different
 *       time. {@code Stopwatch} is a more effective abstraction because it exposes only these
 *       relative values, not the absolute ones.
 *

 *
 *
Basic usage:
 *
 *
{@code
 * Stopwatch stopwatch = Stopwatch.createStarted();
 * doSomething();
 * stopwatch.stop(); // optional
 *
 * Duration duration = stopwatch.elapsed();
 *
 * log.info("time: " + stopwatch); // formatted string like "12.3 ms"
 * }

 *
 *
Stopwatch methods are not idempotent; it is an error to start or stop a stopwatch that is
 * already in the desired state.
 *
 *
When testing code that uses this class, use {@link #createUnstarted(Ticker)} or {@link
 * #createStarted(Ticker)} to supply a fake or mock ticker. This allows you to simulate any valid
 * behavior of the stopwatch.
 *
 *
Note: This class is not thread-safe.
 *
 *
Warning for Android users: a stopwatch with default behavior may not continue to keep
 * time while the device is asleep. Instead, create one like this:
 *
 *
{@code
 * Stopwatch.createStarted(
 *      new Ticker() {
 *        public long read() {
 *          return android.os.SystemClock.elapsedRealtimeNanos();
 *        }
 *      });
 * }

 *
 * @author Kevin Bourrillion
 * @since 10.0
 */
@GwtCompatible(emulated = true)
@SuppressWarnings("GoodTime") // lots of violations
public final class Stopwatch {
  private final Ticker ticker;
  private boolean isRunning;
  private long elapsedNanos;
  private long startTick;

  /**
   * Creates (but does not start) a new stopwatch using {@link System#nanoTime} as its time source.
   *
   * @since 15.0
   */
  public static Stopwatch createUnstarted() {
    return new Stopwatch();
  }

  /**
   * Creates (but does not start) a new stopwatch, using the specified time source.
   *
   * @since 15.0
   */
  public static Stopwatch createUnstarted(Ticker ticker) {
    return new Stopwatch(ticker);
  }

  /**
   * Creates (and starts) a new stopwatch using {@link System#nanoTime} as its time source.
   *
   * @since 15.0
   */
  public static Stopwatch createStarted() {
    return new Stopwatch().start();
  }

  /**
   * Creates (and starts) a new stopwatch, using the specified time source.
   *
   * @since 15.0
   */
  public static Stopwatch createStarted(Ticker ticker) {
    return new Stopwatch(ticker).start();
  }

  Stopwatch() {
    this.ticker = Ticker.systemTicker();
  }

  Stopwatch(Ticker ticker) {
    this.ticker = checkNotNull(ticker, "ticker");
  }

  /**
   * Returns {@code true} if {@link #start()} has been called on this stopwatch, and {@link #stop()}
   * has not been called since the last call to {@code start()}.
   */
  public boolean isRunning() {
    return isRunning;
  }

  /**
   * Starts the stopwatch.
   *
   * @return this {@code Stopwatch} instance
   * @throws IllegalStateException if the stopwatch is already running.
   */
  @CanIgnoreReturnValue
  public Stopwatch start() {
    checkState(!isRunning, "This stopwatch is already running.");
    isRunning = true;
    startTick = ticker.read();
    return this;
  }

  /**
   * Stops the stopwatch. Future reads will return the fixed duration that had elapsed up to this
   * point.
   *
   * @return this {@code Stopwatch} instance
   * @throws IllegalStateException if the stopwatch is already stopped.
   */
  @CanIgnoreReturnValue
  public Stopwatch stop() {
    long tick = ticker.read();
    checkState(isRunning, "This stopwatch is already stopped.");
    isRunning = false;
    elapsedNanos += tick - startTick;
    return this;
  }

  /**
   * Sets the elapsed time for this stopwatch to zero, and places it in a stopped state.
   *
   * @return this {@code Stopwatch} instance
   */
  @CanIgnoreReturnValue
  public Stopwatch reset() {
    elapsedNanos = 0;
    isRunning = false;
    return this;
  }

  private long elapsedNanos() {
    return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
  }

  /**
   * Returns the current elapsed time shown on this stopwatch, expressed in the desired time unit,
   * with any fraction rounded down.
   *
   *
Note: the overhead of measurement can be more than a microsecond, so it is generally
   * not useful to specify {@link TimeUnit#NANOSECONDS} precision here.
   *
   *
It is generally not a good idea to use an ambiguous, unitless {@code long} to represent
   * elapsed time. Therefore, we recommend using {@link #elapsed()} instead, which returns a
   * strongly-typed {@link Duration} instance.
   *
   * @since 14.0 (since 10.0 as {@code elapsedTime()})
   */
  public long elapsed(TimeUnit desiredUnit) {
    return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
  }

  /**
   * Returns the current elapsed time shown on this stopwatch as a {@link Duration}. Unlike {@link
   * #elapsed(TimeUnit)}, this method does not lose any precision due to rounding.
   *
   * @since 22.0
   */
  @GwtIncompatible
  @J2ObjCIncompatible
  public Duration elapsed() {
    return Duration.ofNanos(elapsedNanos());
  }

  /** Returns a string representation of the current elapsed time. */
  @Override
  public String toString() {
    long nanos = elapsedNanos();

    TimeUnit unit = chooseUnit(nanos);
    double value = (double) nanos / NANOSECONDS.convert(1, unit);

    // Too bad this functionality is not exposed as a regular method call
    return Platform.formatCompact4Digits(value) + " " + abbreviate(unit);
  }

  private static TimeUnit chooseUnit(long nanos) {
    if (DAYS.convert(nanos, NANOSECONDS) > 0) {
      return DAYS;
    }
    if (HOURS.convert(nanos, NANOSECONDS) > 0) {
      return HOURS;
    }
    if (MINUTES.convert(nanos, NANOSECONDS) > 0) {
      return MINUTES;
    }
    if (SECONDS.convert(nanos, NANOSECONDS) > 0) {
      return SECONDS;
    }
    if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
      return MILLISECONDS;
    }
    if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
      return MICROSECONDS;
    }
    return NANOSECONDS;
  }

  private static String abbreviate(TimeUnit unit) {
    switch (unit) {
      case NANOSECONDS:
        return "ns";
      case MICROSECONDS:
        return "\u03bcs"; // μs
      case MILLISECONDS:
        return "ms";
      case SECONDS:
        return "s";
      case MINUTES:
        return "min";
      case HOURS:
        return "h";
      case DAYS:
        return "d";
      default:
        throw new AssertionError();
    }
  }
}