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

package com.google.common.net;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Preconditions;
import java.net.InetAddress;
import java.text.ParseException;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A syntactically valid host specifier, suitable for use in a URI. This may be either a numeric IP
 * address in IPv4 or IPv6 notation, or a domain name.
 *
 *
Because this class is intended to represent host specifiers which can reasonably be used in a
 * URI, the domain name case is further restricted to include only those domain names which end in a
 * recognized public suffix; see {@link InternetDomainName#isPublicSuffix()} for details.
 *
 *
Note that no network lookups are performed by any {@code HostSpecifier} methods. No attempt is
 * made to verify that a provided specifier corresponds to a real or accessible host. Only syntactic
 * and pattern-based checks are performed.
 *
 *
If you know that a given string represents a numeric IP address, use {@link InetAddresses} to
 * obtain and manipulate a {@link java.net.InetAddress} instance from it rather than using this
 * class. Similarly, if you know that a given string represents a domain name, use {@link
 * InternetDomainName} rather than this class.
 *
 * @author Craig Berry
 * @since 5.0
 */
@Beta
@GwtIncompatible
public final class HostSpecifier {

  private final String canonicalForm;

  private HostSpecifier(String canonicalForm) {
    this.canonicalForm = canonicalForm;
  }

  /**
   * Returns a {@code HostSpecifier} built from the provided {@code specifier}, which is already
   * known to be valid. If the {@code specifier} might be invalid, use {@link #from(String)}
   * instead.
   *
   *
The specifier must be in one of these formats:
   *
   *

   *
A domain name, like {@code google.com}
   *
A IPv4 address string, like {@code 127.0.0.1}
   *
An IPv6 address string with or without brackets, like {@code [2001:db8::1]} or {@code
   *       2001:db8::1}
   *

   *
   * @throws IllegalArgumentException if the specifier is not valid.
   */
  public static HostSpecifier fromValid(String specifier) {
    // Verify that no port was specified, and strip optional brackets from
    // IPv6 literals.
    final HostAndPort parsedHost = HostAndPort.fromString(specifier);
    Preconditions.checkArgument(!parsedHost.hasPort());
    final String host = parsedHost.getHost();

    // Try to interpret the specifier as an IP address. Note we build
    // the address rather than using the .is* methods because we want to
    // use InetAddresses.toUriString to convert the result to a string in
    // canonical form.
    InetAddress addr = null;
    try {
      addr = InetAddresses.forString(host);
    } catch (IllegalArgumentException e) {
      // It is not an IPv4 or IPv6 literal
    }

    if (addr != null) {
      return new HostSpecifier(InetAddresses.toUriString(addr));
    }

    // It is not any kind of IP address; must be a domain name or invalid.

    // TODO(user): different versions of this for different factories?
    final InternetDomainName domain = InternetDomainName.from(host);

    if (domain.hasPublicSuffix()) {
      return new HostSpecifier(domain.toString());
    }

    throw new IllegalArgumentException(
        "Domain name does not have a recognized public suffix: " + host);
  }

  /**
   * Attempts to return a {@code HostSpecifier} for the given string, throwing an exception if
   * parsing fails. Always use this method in preference to {@link #fromValid(String)} for a
   * specifier that is not already known to be valid.
   *
   * @throws ParseException if the specifier is not valid.
   */
  public static HostSpecifier from(String specifier) throws ParseException {
    try {
      return fromValid(specifier);
    } catch (IllegalArgumentException e) {
      // Since the IAE can originate at several different points inside
      // fromValid(), we implement this method in terms of that one rather
      // than the reverse.

      ParseException parseException = new ParseException("Invalid host specifier: " + specifier, 0);
      parseException.initCause(e);
      throw parseException;
    }
  }

  /**
   * Determines whether {@code specifier} represents a valid {@link HostSpecifier} as described in
   * the documentation for {@link #fromValid(String)}.
   */
  public static boolean isValid(String specifier) {
    try {
      fromValid(specifier);
      return true;
    } catch (IllegalArgumentException e) {
      return false;
    }
  }

  @Override
  public boolean equals(@Nullable Object other) {
    if (this == other) {
      return true;
    }

    if (other instanceof HostSpecifier) {
      final HostSpecifier that = (HostSpecifier) other;
      return this.canonicalForm.equals(that.canonicalForm);
    }

    return false;
  }

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

  /**
   * Returns a string representation of the host specifier suitable for inclusion in a URI. If the
   * host specifier is a domain name, the string will be normalized to all lower case. If the
   * specifier was an IPv6 address without brackets, brackets are added so that the result will be
   * usable in the host part of a URI.
   */
  @Override
  public String toString() {
    return canonicalForm;
  }
}


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

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

import com.google.common.annotations.GwtIncompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;

/**
 * A destination to which bytes can be written, such as a file. Unlike an {@link OutputStream}, a
 * {@code ByteSink} is not an open, stateful stream that can be written to and closed. Instead, it
 * is an immutable supplier of {@code OutputStream} instances.
 *
 *
{@code ByteSink} provides two kinds of methods:
 *
 *

 *
Methods that return a stream: These methods should return a new, independent
 *       instance each time they are called. The caller is responsible for ensuring that the
 *       returned stream is closed.
 *
Convenience methods: These are implementations of common operations that are
 *       typically implemented by opening a stream using one of the methods in the first category,
 *       doing something and finally closing the stream or channel that was opened.
 *

 *
 * @since 14.0
 * @author Colin Decker
 */
@GwtIncompatible
public abstract class ByteSink {

  /** Constructor for use by subclasses. */
  protected ByteSink() {}

  /**
   * Returns a {@link CharSink} view of this {@code ByteSink} that writes characters to this sink as
   * bytes encoded with the given {@link Charset charset}.
   */
  public CharSink asCharSink(Charset charset) {
    return new AsCharSink(charset);
  }

  /**
   * Opens a new {@link OutputStream} for writing to this sink. This method returns a new,
   * independent stream each time it is called.
   *
   *
The caller is responsible for ensuring that the returned stream is closed.
   *
   * @throws IOException if an I/O error occurs while opening the stream
   */
  public abstract OutputStream openStream() throws IOException;

  /**
   * Opens a new buffered {@link OutputStream} for writing to this sink. The returned stream is not
   * required to be a {@link BufferedOutputStream} in order to allow implementations to simply
   * delegate to {@link #openStream()} when the stream returned by that method does not benefit from
   * additional buffering (for example, a {@code ByteArrayOutputStream}). This method returns a new,
   * independent stream each time it is called.
   *
   *
The caller is responsible for ensuring that the returned stream is closed.
   *
   * @throws IOException if an I/O error occurs while opening the stream
   * @since 15.0 (in 14.0 with return type {@link BufferedOutputStream})
   */
  public OutputStream openBufferedStream() throws IOException {
    OutputStream out = openStream();
    return (out instanceof BufferedOutputStream)
        ? (BufferedOutputStream) out
        : new BufferedOutputStream(out);
  }

  /**
   * Writes all the given bytes to this sink.
   *
   * @throws IOException if an I/O occurs while writing to this sink
   */
  public void write(byte[] bytes) throws IOException {
    checkNotNull(bytes);

    Closer closer = Closer.create();
    try {
      OutputStream out = closer.register(openStream());
      out.write(bytes);
      out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
    } catch (Throwable e) {
      throw closer.rethrow(e);
    } finally {
      closer.close();
    }
  }

  /**
   * Writes all the bytes from the given {@code InputStream} to this sink. Does not close {@code
   * input}.
   *
   * @return the number of bytes written
   * @throws IOException if an I/O occurs while reading from {@code input} or writing to this sink
   */
  @CanIgnoreReturnValue
  public long writeFrom(InputStream input) throws IOException {
    checkNotNull(input);

    Closer closer = Closer.create();
    try {
      OutputStream out = closer.register(openStream());
      long written = ByteStreams.copy(input, out);
      out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
      return written;
    } catch (Throwable e) {
      throw closer.rethrow(e);
    } finally {
      closer.close();
    }
  }

  /**
   * A char sink that encodes written characters with a charset and writes resulting bytes to this
   * byte sink.
   */
  private final class AsCharSink extends CharSink {

    private final Charset charset;

    private AsCharSink(Charset charset) {
      this.charset = checkNotNull(charset);
    }

    @Override
    public Writer openStream() throws IOException {
      return new OutputStreamWriter(ByteSink.this.openStream(), charset);
    }

    @Override
    public String toString() {
      return ByteSink.this.toString() + ".asCharSink(" + charset + ")";
    }
  }
}


/*
 * 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.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
import static com.google.common.collect.CollectPreconditions.checkRemove;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.primitives.Ints;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.ObjIntConsumer;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * Basic implementation of {@code Multiset<E>} backed by an instance of {@code Map<E, Count>}.
 *
 *
For serialization to work, the subclass must specify explicit {@code readObject} and {@code
 * writeObject} methods.
 *
 * @author Kevin Bourrillion
 */
@GwtCompatible(emulated = true)
abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E> implements Serializable {
  // TODO(lowasser): consider overhauling this back to Map<E, Integer>
  private transient Map<E, Count> backingMap;

  /*
   * Cache the size for efficiency. Using a long lets us avoid the need for
   * overflow checking and ensures that size() will function correctly even if
   * the multiset had once been larger than Integer.MAX_VALUE.
   */
  private transient long size;

  /** Standard constructor. */
  protected AbstractMapBasedMultiset(Map<E, Count> backingMap) {
    checkArgument(backingMap.isEmpty());
    this.backingMap = backingMap;
  }

  /** Used during deserialization only. The backing map must be empty. */
  void setBackingMap(Map<E, Count> backingMap) {
    this.backingMap = backingMap;
  }

  // Required Implementations

  /**
   * {@inheritDoc}
   *
   *
Invoking {@link Multiset.Entry#getCount} on an entry in the returned set always returns the
   * current count of that element in the multiset, as opposed to the count at the time the entry
   * was retrieved.
   */
  @Override
  public Set<Multiset.Entry<E>> entrySet() {
    return super.entrySet();
  }

  @Override
  Iterator<E> elementIterator() {
    final Iterator<Map.Entry<E, Count>> backingEntries = backingMap.entrySet().iterator();
    return new Iterator<E>() {
      Map.@Nullable Entry<E, Count> toRemove;

      @Override
      public boolean hasNext() {
        return backingEntries.hasNext();
      }

      @Override
      public E next() {
        final Map.Entry<E, Count> mapEntry = backingEntries.next();
        toRemove = mapEntry;
        return mapEntry.getKey();
      }

      @Override
      public void remove() {
        checkRemove(toRemove != null);
        size -= toRemove.getValue().getAndSet(0);
        backingEntries.remove();
        toRemove = null;
      }
    };
  }

  @Override
  Iterator<Entry<E>> entryIterator() {
    final Iterator<Map.Entry<E, Count>> backingEntries = backingMap.entrySet().iterator();
    return new Iterator<Multiset.Entry<E>>() {
      Map.@Nullable Entry<E, Count> toRemove;

      @Override
      public boolean hasNext() {
        return backingEntries.hasNext();
      }

      @Override
      public Multiset.Entry<E> next() {
        final Map.Entry<E, Count> mapEntry = backingEntries.next();
        toRemove = mapEntry;
        return new Multisets.AbstractEntry<E>() {
          @Override
          public E getElement() {
            return mapEntry.getKey();
          }

          @Override
          public int getCount() {
            Count count = mapEntry.getValue();
            if (count == null || count.get() == 0) {
              Count frequency = backingMap.get(getElement());
              if (frequency != null) {
                return frequency.get();
              }
            }
            return (count == null) ? 0 : count.get();
          }
        };
      }

      @Override
      public void remove() {
        checkRemove(toRemove != null);
        size -= toRemove.getValue().getAndSet(0);
        backingEntries.remove();
        toRemove = null;
      }
    };
  }

  @Override
  public void forEachEntry(ObjIntConsumer<? super E> action) {
    checkNotNull(action);
    backingMap.forEach((element, count) -> action.accept(element, count.get()));
  }

  @Override
  public void clear() {
    for (Count frequency : backingMap.values()) {
      frequency.set(0);
    }
    backingMap.clear();
    size = 0L;
  }

  @Override
  int distinctElements() {
    return backingMap.size();
  }

  // Optimizations - Query Operations

  @Override
  public int size() {
    return Ints.saturatedCast(size);
  }

  @Override
  public Iterator<E> iterator() {
    return new MapBasedMultisetIterator();
  }

  /*
   * Not subclassing AbstractMultiset$MultisetIterator because next() needs to
   * retrieve the Map.Entry<E, Count> entry, which can then be used for
   * a more efficient remove() call.
   */
  private class MapBasedMultisetIterator implements Iterator<E> {
    final Iterator<Map.Entry<E, Count>> entryIterator;
    Map.@MonotonicNonNull Entry<E, Count> currentEntry;
    int occurrencesLeft;
    boolean canRemove;

    MapBasedMultisetIterator() {
      this.entryIterator = backingMap.entrySet().iterator();
    }

    @Override
    public boolean hasNext() {
      return occurrencesLeft > 0 || entryIterator.hasNext();
    }

    @Override
    public E next() {
      if (occurrencesLeft == 0) {
        currentEntry = entryIterator.next();
        occurrencesLeft = currentEntry.getValue().get();
      }
      occurrencesLeft--;
      canRemove = true;
      return currentEntry.getKey();
    }

    @Override
    public void remove() {
      checkRemove(canRemove);
      int frequency = currentEntry.getValue().get();
      if (frequency <= 0) {
        throw new ConcurrentModificationException();
      }
      if (currentEntry.getValue().addAndGet(-1) == 0) {
        entryIterator.remove();
      }
      size--;
      canRemove = false;
    }
  }

  @Override
  public int count(@Nullable Object element) {
    Count frequency = Maps.safeGet(backingMap, element);
    return (frequency == null) ? 0 : frequency.get();
  }

  // Optional Operations - Modification Operations

  /**
   * {@inheritDoc}
   *
   * @throws IllegalArgumentException if the call would result in more than {@link
   *     Integer#MAX_VALUE} occurrences of {@code element} in this multiset.
   */
  @CanIgnoreReturnValue
  @Override
  public int add(@Nullable E element, int occurrences) {
    if (occurrences == 0) {
      return count(element);
    }
    checkArgument(occurrences > 0, "occurrences cannot be negative: %s", occurrences);
    Count frequency = backingMap.get(element);
    int oldCount;
    if (frequency == null) {
      oldCount = 0;
      backingMap.put(element, new Count(occurrences));
    } else {
      oldCount = frequency.get();
      long newCount = (long) oldCount + (long) occurrences;
      checkArgument(newCount <= Integer.MAX_VALUE, "too many occurrences: %s", newCount);
      frequency.add(occurrences);
    }
    size += occurrences;
    return oldCount;
  }

  @CanIgnoreReturnValue
  @Override
  public int remove(@Nullable Object element, int occurrences) {
    if (occurrences == 0) {
      return count(element);
    }
    checkArgument(occurrences > 0, "occurrences cannot be negative: %s", occurrences);
    Count frequency = backingMap.get(element);
    if (frequency == null) {
      return 0;
    }

    int oldCount = frequency.get();

    int numberRemoved;
    if (oldCount > occurrences) {
      numberRemoved = occurrences;
    } else {
      numberRemoved = oldCount;
      backingMap.remove(element);
    }

    frequency.add(-numberRemoved);
    size -= numberRemoved;
    return oldCount;
  }

  // Roughly a 33% performance improvement over AbstractMultiset.setCount().
  @CanIgnoreReturnValue
  @Override
  public int setCount(@Nullable E element, int count) {
    checkNonnegative(count, "count");

    Count existingCounter;
    int oldCount;
    if (count == 0) {
      existingCounter = backingMap.remove(element);
      oldCount = getAndSet(existingCounter, count);
    } else {
      existingCounter = backingMap.get(element);
      oldCount = getAndSet(existingCounter, count);

      if (existingCounter == null) {
        backingMap.put(element, new Count(count));
      }
    }

    size += (count - oldCount);
    return oldCount;
  }

  private static int getAndSet(@Nullable Count i, int count) {
    if (i == null) {
      return 0;
    }

    return i.getAndSet(count);
  }

  // Don't allow default serialization.
  @GwtIncompatible // java.io.ObjectStreamException
  private void readObjectNoData() throws ObjectStreamException {
    throw new InvalidObjectException("Stream data required");
  }

  @GwtIncompatible // not needed in emulated source.
  private static final long serialVersionUID = -2250766705698539974L;
}


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

import static com.google.common.base.Strings.lenientFormat;

import com.google.common.annotations.GwtCompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * Static convenience methods that serve the same purpose as Java language assertions,
 * except that they are always enabled. These methods should be used instead of Java assertions
 * whenever there is a chance the check may fail "in real life". Example:
 *
 *
{@code
 * Bill bill = remoteService.getLastUnpaidBill();
 *
 * // In case bug 12345 happens again we'd rather just die
 * Verify.verify(bill.status() == Status.UNPAID,
 *     "Unexpected bill status: %s", bill.status());
 * }

 *
 *
Comparison to alternatives

 *
 *
Note: In some cases the differences explained below can be subtle. When it's unclear
 * which approach to use, don't worry too much about it; just pick something that seems
 * reasonable and it will be fine.
 *
 *

 *
If checking whether the caller has violated your method or constructor's contract
 *       (such as by passing an invalid argument), use the utilities of the {@link Preconditions}
 *       class instead.
 *
If checking an impossible condition (which cannot happen unless your own
 *       class or its trusted dependencies is badly broken), this is what ordinary Java
 *       assertions are for. Note that assertions are not enabled by default; they are essentially
 *       considered "compiled comments."
 *
An explicit {@code if/throw} (as illustrated below) is always acceptable; we still
 *       recommend using our {@link VerifyException} exception type. Throwing a plain {@link
 *       RuntimeException} is frowned upon.
 *
Use of {@link java.util.Objects#requireNonNull(Object)} is generally discouraged, since
 *       {@link #verifyNotNull(Object)} and {@link Preconditions#checkNotNull(Object)} perform the
 *       same function with more clarity.
 *

 *
 *
Warning about performance

 *
 *
Remember that parameter values for message construction must all be computed eagerly, and
 * autoboxing and varargs array creation may happen as well, even when the verification succeeds and
 * the message ends up unneeded. Performance-sensitive verification checks should continue to use
 * usual form:
 *
 *
{@code
 * Bill bill = remoteService.getLastUnpaidBill();
 * if (bill.status() != Status.UNPAID) {
 *   throw new VerifyException("Unexpected bill status: " + bill.status());
 * }
 * }

 *
 *
Only {@code %s} is supported

 *
 *
As with {@link Preconditions}, {@code Verify} uses {@link Strings#lenientFormat} to format
 * error message template strings. This only supports the {@code "%s"} specifier, not the full range
 * of {@link java.util.Formatter} specifiers. However, note that if the number of arguments does not
 * match the number of occurrences of {@code "%s"} in the format string, {@code Verify} will still
 * behave as expected, and will still include all argument values in the error message; the message
 * will simply not be formatted exactly as intended.
 *
 *
More information

 *
 * See Conditional
 * failures explained in the Guava User Guide for advice on when this class should be used.
 *
 * @since 17.0
 */
@GwtCompatible
public final class Verify {
  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with no
   * message otherwise.
   *
   * @throws VerifyException if {@code expression} is {@code false}
   * @see Preconditions#checkState Preconditions.checkState()
   */
  public static void verify(boolean expression) {
    if (!expression) {
      throw new VerifyException();
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   * @param expression a boolean expression
   * @param errorMessageTemplate a template for the exception message should the check fail. The
   *     message is formed by replacing each {@code %s} placeholder in the template with an
   *     argument. These are matched by position - the first {@code %s} gets {@code
   *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
   *     square braces. Unmatched placeholders will be left as-is.
   * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
   *     are converted to strings using {@link String#valueOf(Object)}.
   * @throws VerifyException if {@code expression} is {@code false}
   * @see Preconditions#checkState Preconditions.checkState()
   */
  public static void verify(
      boolean expression,
      @Nullable String errorMessageTemplate,
      @Nullable Object @Nullable ... errorMessageArgs) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, errorMessageArgs));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(boolean expression, @Nullable String errorMessageTemplate, char p1) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(boolean expression, @Nullable String errorMessageTemplate, int p1) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(boolean expression, @Nullable String errorMessageTemplate, long p1) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, @Nullable Object p1) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, char p1, char p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, int p1, char p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, long p1, char p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, @Nullable Object p1, char p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, char p1, int p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, int p1, int p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, long p1, int p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, @Nullable Object p1, int p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, char p1, long p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, int p1, long p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, long p1, long p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, @Nullable Object p1, long p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, char p1, @Nullable Object p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, int p1, @Nullable Object p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression, @Nullable String errorMessageTemplate, long p1, @Nullable Object p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression,
      @Nullable String errorMessageTemplate,
      @Nullable Object p1,
      @Nullable Object p2) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression,
      @Nullable String errorMessageTemplate,
      @Nullable Object p1,
      @Nullable Object p2,
      @Nullable Object p3) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2, p3));
    }
  }

  /**
   * Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
   * custom message otherwise.
   *
   *
See {@link #verify(boolean, String, Object...)} for details.
   *
   * @since 23.1 (varargs overload since 17.0)
   */
  public static void verify(
      boolean expression,
      @Nullable String errorMessageTemplate,
      @Nullable Object p1,
      @Nullable Object p2,
      @Nullable Object p3,
      @Nullable Object p4) {
    if (!expression) {
      throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2, p3, p4));
    }
  }

  /**
   * Ensures that {@code reference} is non-null, throwing a {@code VerifyException} with a default
   * message otherwise.
   *
   * @return {@code reference}, guaranteed to be non-null, for convenience
   * @throws VerifyException if {@code reference} is {@code null}
   * @see Preconditions#checkNotNull Preconditions.checkNotNull()
   */
  @CanIgnoreReturnValue
  public static <T> T verifyNotNull(@Nullable T reference) {
    return verifyNotNull(reference, "expected a non-null reference");
  }

  /**
   * Ensures that {@code reference} is non-null, throwing a {@code VerifyException} with a custom
   * message otherwise.
   *
   * @param errorMessageTemplate a template for the exception message should the check fail. The
   *     message is formed by replacing each {@code %s} placeholder in the template with an
   *     argument. These are matched by position - the first {@code %s} gets {@code
   *     errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
   *     square braces. Unmatched placeholders will be left as-is.
   * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
   *     are converted to strings using {@link String#valueOf(Object)}.
   * @return {@code reference}, guaranteed to be non-null, for convenience
   * @throws VerifyException if {@code reference} is {@code null}
   * @see Preconditions#checkNotNull Preconditions.checkNotNull()
   */
  @CanIgnoreReturnValue
  public static <T> T verifyNotNull(
      @Nullable T reference,
      @Nullable String errorMessageTemplate,
      @Nullable Object @Nullable ... errorMessageArgs) {
    verify(reference != null, errorMessageTemplate, errorMessageArgs);
    return reference;
  }

  // TODO(kevinb): consider <T> T verifySingleton(Iterable<T>) to take over for
  // Iterables.getOnlyElement()

  private Verify() {}
}


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

package com.google.common.collect;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Preconditions;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * Static utility methods pertaining to {@link Queue} and {@link Deque} instances. Also see this
 * class's counterparts {@link Lists}, {@link Sets}, and {@link Maps}.
 *
 * @author Kurt Alfred Kluever
 * @since 11.0
 */
@GwtCompatible(emulated = true)
public final class Queues {
  private Queues() {}

  // ArrayBlockingQueue

  /**
   * Creates an empty {@code ArrayBlockingQueue} with the given (fixed) capacity and nonfair access
   * policy.
   */
  @GwtIncompatible // ArrayBlockingQueue
  public static <E> ArrayBlockingQueue<E> newArrayBlockingQueue(int capacity) {
    return new ArrayBlockingQueue<E>(capacity);
  }

  // ArrayDeque

  /**
   * Creates an empty {@code ArrayDeque}.
   *
   * @since 12.0
   */
  public static <E> ArrayDeque<E> newArrayDeque() {
    return new ArrayDeque<E>();
  }

  /**
   * Creates an {@code ArrayDeque} containing the elements of the specified iterable, in the order
   * they are returned by the iterable's iterator.
   *
   * @since 12.0
   */
  public static <E> ArrayDeque<E> newArrayDeque(Iterable<? extends E> elements) {
    if (elements instanceof Collection) {
      return new ArrayDeque<E>(Collections2.cast(elements));
    }
    ArrayDeque<E> deque = new ArrayDeque<E>();
    Iterables.addAll(deque, elements);
    return deque;
  }

  // ConcurrentLinkedQueue

  /** Creates an empty {@code ConcurrentLinkedQueue}. */
  @GwtIncompatible // ConcurrentLinkedQueue
  public static <E> ConcurrentLinkedQueue<E> newConcurrentLinkedQueue() {
    return new ConcurrentLinkedQueue<E>();
  }

  /**
   * Creates a {@code ConcurrentLinkedQueue} containing the elements of the specified iterable, in
   * the order they are returned by the iterable's iterator.
   */
  @GwtIncompatible // ConcurrentLinkedQueue
  public static <E> ConcurrentLinkedQueue<E> newConcurrentLinkedQueue(
      Iterable<? extends E> elements) {
    if (elements instanceof Collection) {
      return new ConcurrentLinkedQueue<E>(Collections2.cast(elements));
    }
    ConcurrentLinkedQueue<E> queue = new ConcurrentLinkedQueue<E>();
    Iterables.addAll(queue, elements);
    return queue;
  }

  // LinkedBlockingDeque

  /**
   * Creates an empty {@code LinkedBlockingDeque} with a capacity of {@link Integer#MAX_VALUE}.
   *
   * @since 12.0
   */
  @GwtIncompatible // LinkedBlockingDeque
  public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque() {
    return new LinkedBlockingDeque<E>();
  }

  /**
   * Creates an empty {@code LinkedBlockingDeque} with the given (fixed) capacity.
   *
   * @throws IllegalArgumentException if {@code capacity} is less than 1
   * @since 12.0
   */
  @GwtIncompatible // LinkedBlockingDeque
  public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(int capacity) {
    return new LinkedBlockingDeque<E>(capacity);
  }

  /**
   * Creates a {@code LinkedBlockingDeque} with a capacity of {@link Integer#MAX_VALUE}, containing
   * the elements of the specified iterable, in the order they are returned by the iterable's
   * iterator.
   *
   * @since 12.0
   */
  @GwtIncompatible // LinkedBlockingDeque
  public static <E> LinkedBlockingDeque<E> newLinkedBlockingDeque(Iterable<? extends E> elements) {
    if (elements instanceof Collection) {
      return new LinkedBlockingDeque<E>(Collections2.cast(elements));
    }
    LinkedBlockingDeque<E> deque = new LinkedBlockingDeque<E>();
    Iterables.addAll(deque, elements);
    return deque;
  }

  // LinkedBlockingQueue

  /** Creates an empty {@code LinkedBlockingQueue} with a capacity of {@link Integer#MAX_VALUE}. */
  @GwtIncompatible // LinkedBlockingQueue
  public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue() {
    return new LinkedBlockingQueue<E>();
  }

  /**
   * Creates an empty {@code LinkedBlockingQueue} with the given (fixed) capacity.
   *
   * @throws IllegalArgumentException if {@code capacity} is less than 1
   */
  @GwtIncompatible // LinkedBlockingQueue
  public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue(int capacity) {
    return new LinkedBlockingQueue<E>(capacity);
  }

  /**
   * Creates a {@code LinkedBlockingQueue} with a capacity of {@link Integer#MAX_VALUE}, containing
   * the elements of the specified iterable, in the order they are returned by the iterable's
   * iterator.
   *
   * @param elements the elements that the queue should contain, in order
   * @return a new {@code LinkedBlockingQueue} containing those elements
   */
  @GwtIncompatible // LinkedBlockingQueue
  public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue(Iterable<? extends E> elements) {
    if (elements instanceof Collection) {
      return new LinkedBlockingQueue<E>(Collections2.cast(elements));
    }
    LinkedBlockingQueue<E> queue = new LinkedBlockingQueue<E>();
    Iterables.addAll(queue, elements);
    return queue;
  }

  // LinkedList: see {@link com.google.common.collect.Lists}

  // PriorityBlockingQueue

  /**
   * Creates an empty {@code PriorityBlockingQueue} with the ordering given by its elements' natural
   * ordering.
   *
   * @since 11.0 (requires that {@code E} be {@code Comparable} since 15.0).
   */
  @GwtIncompatible // PriorityBlockingQueue
  public static <E extends Comparable> PriorityBlockingQueue<E> newPriorityBlockingQueue() {
    return new PriorityBlockingQueue<E>();
  }

  /**
   * Creates a {@code PriorityBlockingQueue} containing the given elements.
   *
   *
Note: If the specified iterable is a {@code SortedSet} or a {@code PriorityQueue},
   * this priority queue will be ordered according to the same ordering.
   *
   * @since 11.0 (requires that {@code E} be {@code Comparable} since 15.0).
   */
  @GwtIncompatible // PriorityBlockingQueue
  public static <E extends Comparable> PriorityBlockingQueue<E> newPriorityBlockingQueue(
      Iterable<? extends E> elements) {
    if (elements instanceof Collection) {
      return new PriorityBlockingQueue<E>(Collections2.cast(elements));
    }
    PriorityBlockingQueue<E> queue = new PriorityBlockingQueue<E>();
    Iterables.addAll(queue, elements);
    return queue;
  }

  // PriorityQueue

  /**
   * Creates an empty {@code PriorityQueue} with the ordering given by its elements' natural
   * ordering.
   *
   * @since 11.0 (requires that {@code E} be {@code Comparable} since 15.0).
   */
  public static <E extends Comparable> PriorityQueue<E> newPriorityQueue() {
    return new PriorityQueue<E>();
  }

  /**
   * Creates a {@code PriorityQueue} containing the given elements.
   *
   *
Note: If the specified iterable is a {@code SortedSet} or a {@code PriorityQueue},
   * this priority queue will be ordered according to the same ordering.
   *
   * @since 11.0 (requires that {@code E} be {@code Comparable} since 15.0).
   */
  public static <E extends Comparable> PriorityQueue<E> newPriorityQueue(
      Iterable<? extends E> elements) {
    if (elements instanceof Collection) {
      return new PriorityQueue<E>(Collections2.cast(elements));
    }
    PriorityQueue<E> queue = new PriorityQueue<E>();
    Iterables.addAll(queue, elements);
    return queue;
  }

  // SynchronousQueue

  /** Creates an empty {@code SynchronousQueue} with nonfair access policy. */
  @GwtIncompatible // SynchronousQueue
  public static <E> SynchronousQueue<E> newSynchronousQueue() {
    return new SynchronousQueue<E>();
  }

  /**
   * Drains the queue as {@link BlockingQueue#drainTo(Collection, int)}, but if the requested {@code
   * numElements} elements are not available, it will wait for them up to the specified timeout.
   *
   * @param q the blocking queue to be drained
   * @param buffer where to add the transferred elements
   * @param numElements the number of elements to be waited for
   * @param timeout how long to wait before giving up, in units of {@code unit}
   * @param unit a {@code TimeUnit} determining how to interpret the timeout parameter
   * @return the number of elements transferred
   * @throws InterruptedException if interrupted while waiting
   */
  @Beta
  @CanIgnoreReturnValue
  @GwtIncompatible // BlockingQueue
  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
  public static <E> int drain(
      BlockingQueue<E> q,
      Collection<? super E> buffer,
      int numElements,
      long timeout,
      TimeUnit unit)
      throws InterruptedException {
    Preconditions.checkNotNull(buffer);
    /*
     * This code performs one System.nanoTime() more than necessary, and in return, the time to
     * execute Queue#drainTo is not added *on top* of waiting for the timeout (which could make
     * the timeout arbitrarily inaccurate, given a queue that is slow to drain).
     */
    long deadline = System.nanoTime() + unit.toNanos(timeout);
    int added = 0;
    while (added < numElements) {
      // we could rely solely on #poll, but #drainTo might be more efficient when there are multiple
      // elements already available (e.g. LinkedBlockingQueue#drainTo locks only once)
      added += q.drainTo(buffer, numElements - added);
      if (added < numElements) { // not enough elements immediately available; will have to poll
        E e = q.poll(deadline - System.nanoTime(), TimeUnit.NANOSECONDS);
        if (e == null) {
          break; // we already waited enough, and there are no more elements in sight
        }
        buffer.add(e);
        added++;
      }
    }
    return added;
  }

  /**
   * Drains the queue as {@linkplain #drain(BlockingQueue, Collection, int, long, TimeUnit)}, but
   * with a different behavior in case it is interrupted while waiting. In that case, the operation
   * will continue as usual, and in the end the thread's interruption status will be set (no {@code
   * InterruptedException} is thrown).
   *
   * @param q the blocking queue to be drained
   * @param buffer where to add the transferred elements
   * @param numElements the number of elements to be waited for
   * @param timeout how long to wait before giving up, in units of {@code unit}
   * @param unit a {@code TimeUnit} determining how to interpret the timeout parameter
   * @return the number of elements transferred
   */
  @Beta
  @CanIgnoreReturnValue
  @GwtIncompatible // BlockingQueue
  @SuppressWarnings("GoodTime") // should accept a java.time.Duration
  public static <E> int drainUninterruptibly(
      BlockingQueue<E> q,
      Collection<? super E> buffer,
      int numElements,
      long timeout,
      TimeUnit unit) {
    Preconditions.checkNotNull(buffer);
    long deadline = System.nanoTime() + unit.toNanos(timeout);
    int added = 0;
    boolean interrupted = false;
    try {
      while (added < numElements) {
        // we could rely solely on #poll, but #drainTo might be more efficient when there are
        // multiple elements already available (e.g. LinkedBlockingQueue#drainTo locks only once)
        added += q.drainTo(buffer, numElements - added);
        if (added < numElements) { // not enough elements immediately available; will have to poll
          E e; // written exactly once, by a successful (uninterrupted) invocation of #poll
          while (true) {
            try {
              e = q.poll(deadline - System.nanoTime(), TimeUnit.NANOSECONDS);
              break;
            } catch (InterruptedException ex) {
              interrupted = true; // note interruption and retry
            }
          }
          if (e == null) {
            break; // we already waited enough, and there are no more elements in sight
          }
          buffer.add(e);
          added++;
        }
      }
    } finally {
      if (interrupted) {
        Thread.currentThread().interrupt();
      }
    }
    return added;
  }

  /**
   * Returns a synchronized (thread-safe) queue backed by the specified queue. In order to guarantee
   * serial access, it is critical that all access to the backing queue is accomplished
   * through the returned queue.
   *
   *
It is imperative that the user manually synchronize on the returned queue when accessing the
   * queue's iterator:
   *
   *
{@code
   * Queue<E> queue = Queues.synchronizedQueue(MinMaxPriorityQueue.<E>create());
   * ...
   * queue.add(element);  // Needn't be in synchronized block
   * ...
   * synchronized (queue) {  // Must synchronize on queue!
   *   Iterator<E> i = queue.iterator(); // Must be in synchronized block
   *   while (i.hasNext()) {
   *     foo(i.next());
   *   }
   * }
   * }

   *
   *
Failure to follow this advice may result in non-deterministic behavior.
   *
   *
The returned queue will be serializable if the specified queue is serializable.
   *
   * @param queue the queue to be wrapped in a synchronized view
   * @return a synchronized view of the specified queue
   * @since 14.0
   */
  public static <E> Queue<E> synchronizedQueue(Queue<E> queue) {
    return Synchronized.queue(queue, null);
  }

  /**
   * Returns a synchronized (thread-safe) deque backed by the specified deque. In order to guarantee
   * serial access, it is critical that all access to the backing deque is accomplished
   * through the returned deque.
   *
   *
It is imperative that the user manually synchronize on the returned deque when accessing any
   * of the deque's iterators:
   *
   *
{@code
   * Deque<E> deque = Queues.synchronizedDeque(Queues.<E>newArrayDeque());
   * ...
   * deque.add(element);  // Needn't be in synchronized block
   * ...
   * synchronized (deque) {  // Must synchronize on deque!
   *   Iterator<E> i = deque.iterator(); // Must be in synchronized block
   *   while (i.hasNext()) {
   *     foo(i.next());
   *   }
   * }
   * }

   *
   *
Failure to follow this advice may result in non-deterministic behavior.
   *
   *
The returned deque will be serializable if the specified deque is serializable.
   *
   * @param deque the deque to be wrapped in a synchronized view
   * @return a synchronized view of the specified deque
   * @since 15.0
   */
  public static <E> Deque<E> synchronizedDeque(Deque<E> deque) {
    return Synchronized.deque(deque, null);
  }
}


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

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.alwaysTrue;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.in;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Maps.safeContainsKey;
import static com.google.common.collect.Maps.safeGet;

import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps.IteratorBasedAbstractMap;
import com.google.common.collect.Maps.ViewCachingAbstractMap;
import com.google.common.collect.Sets.ImprovedAbstractSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.j2objc.annotations.WeakOuter;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.checkerframework.checker.nullness.compatqual.MonotonicNonNullDecl;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * {@link Table} implementation backed by a map that associates row keys with column key / value
 * secondary maps. This class provides rapid access to records by the row key alone or by both keys,
 * but not by just the column key.
 *
 *
The views returned by {@link #column}, {@link #columnKeySet()}, and {@link #columnMap()} have
 * iterators that don't support {@code remove()}. Otherwise, all optional operations are supported.
 * Null row keys, columns keys, and values are not supported.
 *
 *
Lookups by row key are often faster than lookups by column key, because the data is stored in
 * a {@code Map<R, Map<C, V>>}. A method call like {@code column(columnKey).get(rowKey)} still runs
 * quickly, since the row key is provided. However, {@code column(columnKey).size()} takes longer,
 * since an iteration across all row keys occurs.
 *
 *
Note that this implementation is not synchronized. If multiple threads access this table
 * concurrently and one of the threads modifies the table, it must be synchronized externally.
 *
 * @author Jared Levy
 */
@GwtCompatible
class StandardTable<R, C, V> extends AbstractTable<R, C, V> implements Serializable {
  @GwtTransient final Map<R, Map<C, V>> backingMap;
  @GwtTransient final Supplier<? extends Map<C, V>> factory;

  StandardTable(Map<R, Map<C, V>> backingMap, Supplier<? extends Map<C, V>> factory) {
    this.backingMap = backingMap;
    this.factory = factory;
  }

  // Accessors

  @Override
  public boolean contains(@NullableDecl Object rowKey, @NullableDecl Object columnKey) {
    return rowKey != null && columnKey != null && super.contains(rowKey, columnKey);
  }

  @Override
  public boolean containsColumn(@NullableDecl Object columnKey) {
    if (columnKey == null) {
      return false;
    }
    for (Map<C, V> map : backingMap.values()) {
      if (safeContainsKey(map, columnKey)) {
        return true;
      }
    }
    return false;
  }

  @Override
  public boolean containsRow(@NullableDecl Object rowKey) {
    return rowKey != null && safeContainsKey(backingMap, rowKey);
  }

  @Override
  public boolean containsValue(@NullableDecl Object value) {
    return value != null && super.containsValue(value);
  }

  @Override
  public V get(@NullableDecl Object rowKey, @NullableDecl Object columnKey) {
    return (rowKey == null || columnKey == null) ? null : super.get(rowKey, columnKey);
  }

  @Override
  public boolean isEmpty() {
    return backingMap.isEmpty();
  }

  @Override
  public int size() {
    int size = 0;
    for (Map<C, V> map : backingMap.values()) {
      size += map.size();
    }
    return size;
  }

  // Mutators

  @Override
  public void clear() {
    backingMap.clear();
  }

  private Map<C, V> getOrCreate(R rowKey) {
    Map<C, V> map = backingMap.get(rowKey);
    if (map == null) {
      map = factory.get();
      backingMap.put(rowKey, map);
    }
    return map;
  }

  @CanIgnoreReturnValue
  @Override
  public V put(R rowKey, C columnKey, V value) {
    checkNotNull(rowKey);
    checkNotNull(columnKey);
    checkNotNull(value);
    return getOrCreate(rowKey).put(columnKey, value);
  }

  @CanIgnoreReturnValue
  @Override
  public V remove(@NullableDecl Object rowKey, @NullableDecl Object columnKey) {
    if ((rowKey == null) || (columnKey == null)) {
      return null;
    }
    Map<C, V> map = safeGet(backingMap, rowKey);
    if (map == null) {
      return null;
    }
    V value = map.remove(columnKey);
    if (map.isEmpty()) {
      backingMap.remove(rowKey);
    }
    return value;
  }

  @CanIgnoreReturnValue
  private Map<R, V> removeColumn(Object column) {
    Map<R, V> output = new LinkedHashMap<>();
    Iterator<Entry<R, Map<C, V>>> iterator = backingMap.entrySet().iterator();
    while (iterator.hasNext()) {
      Entry<R, Map<C, V>> entry = iterator.next();
      V value = entry.getValue().remove(column);
      if (value != null) {
        output.put(entry.getKey(), value);
        if (entry.getValue().isEmpty()) {
          iterator.remove();
        }
      }
    }
    return output;
  }

  private boolean containsMapping(Object rowKey, Object columnKey, Object value) {
    return value != null && value.equals(get(rowKey, columnKey));
  }

  /** Remove a row key / column key / value mapping, if present. */
  private boolean removeMapping(Object rowKey, Object columnKey, Object value) {
    if (containsMapping(rowKey, columnKey, value)) {
      remove(rowKey, columnKey);
      return true;
    }
    return false;
  }

  // Views

  /**
   * Abstract set whose {@code isEmpty()} returns whether the table is empty and whose {@code
   * clear()} clears all table mappings.
   */
  @WeakOuter
  private abstract class TableSet<T> extends ImprovedAbstractSet<T> {
    @Override
    public boolean isEmpty() {
      return backingMap.isEmpty();
    }

    @Override
    public void clear() {
      backingMap.clear();
    }
  }

  /**
   * {@inheritDoc}
   *
   *
The set's iterator traverses the mappings for the first row, the mappings for the second
   * row, and so on.
   *
   *
Each cell is an immutable snapshot of a row key / column key / value mapping, taken at the
   * time the cell is returned by a method call to the set or its iterator.
   */
  @Override
  public Set<Cell<R, C, V>> cellSet() {
    return super.cellSet();
  }

  @Override
  Iterator<Cell<R, C, V>> cellIterator() {
    return new CellIterator();
  }

  private class CellIterator implements Iterator<Cell<R, C, V>> {
    final Iterator<Entry<R, Map<C, V>>> rowIterator = backingMap.entrySet().iterator();
    @NullableDecl Entry<R, Map<C, V>> rowEntry;
    Iterator<Entry<C, V>> columnIterator = Iterators.emptyModifiableIterator();

    @Override
    public boolean hasNext() {
      return rowIterator.hasNext() || columnIterator.hasNext();
    }

    @Override
    public Cell<R, C, V> next() {
      if (!columnIterator.hasNext()) {
        rowEntry = rowIterator.next();
        columnIterator = rowEntry.getValue().entrySet().iterator();
      }
      Entry<C, V> columnEntry = columnIterator.next();
      return Tables.immutableCell(rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
    }

    @Override
    public void remove() {
      columnIterator.remove();
      if (rowEntry.getValue().isEmpty()) {
        rowIterator.remove();
        rowEntry = null;
      }
    }
  }

  @Override
  public Map<C, V> row(R rowKey) {
    return new Row(rowKey);
  }

  class Row extends IteratorBasedAbstractMap<C, V> {
    final R rowKey;

    Row(R rowKey) {
      this.rowKey = checkNotNull(rowKey);
    }

    @NullableDecl Map<C, V> backingRowMap;

    Map<C, V> backingRowMap() {
      return (backingRowMap == null || (backingRowMap.isEmpty() && backingMap.containsKey(rowKey)))
          ? backingRowMap = computeBackingRowMap()
          : backingRowMap;
    }

    Map<C, V> computeBackingRowMap() {
      return backingMap.get(rowKey);
    }

    // Call this every time we perform a removal.
    void maintainEmptyInvariant() {
      if (backingRowMap() != null && backingRowMap.isEmpty()) {
        backingMap.remove(rowKey);
        backingRowMap = null;
      }
    }

    @Override
    public boolean containsKey(Object key) {
      Map<C, V> backingRowMap = backingRowMap();
      return (key != null && backingRowMap != null) && Maps.safeContainsKey(backingRowMap, key);
    }

    @Override
    public V get(Object key) {
      Map<C, V> backingRowMap = backingRowMap();
      return (key != null && backingRowMap != null) ? Maps.safeGet(backingRowMap, key) : null;
    }

    @Override
    public V put(C key, V value) {
      checkNotNull(key);
      checkNotNull(value);
      if (backingRowMap != null && !backingRowMap.isEmpty()) {
        return backingRowMap.put(key, value);
      }
      return StandardTable.this.put(rowKey, key, value);
    }

    @Override
    public V remove(Object key) {
      Map<C, V> backingRowMap = backingRowMap();
      if (backingRowMap == null) {
        return null;
      }
      V result = Maps.safeRemove(backingRowMap, key);
      maintainEmptyInvariant();
      return result;
    }

    @Override
    public void clear() {
      Map<C, V> backingRowMap = backingRowMap();
      if (backingRowMap != null) {
        backingRowMap.clear();
      }
      maintainEmptyInvariant();
    }

    @Override
    public int size() {
      Map<C, V> map = backingRowMap();
      return (map == null) ? 0 : map.size();
    }

    @Override
    Iterator<Entry<C, V>> entryIterator() {
      final Map<C, V> map = backingRowMap();
      if (map == null) {
        return Iterators.emptyModifiableIterator();
      }
      final Iterator<Entry<C, V>> iterator = map.entrySet().iterator();
      return new Iterator<Entry<C, V>>() {
        @Override
        public boolean hasNext() {
          return iterator.hasNext();
        }

        @Override
        public Entry<C, V> next() {
          return wrapEntry(iterator.next());
        }

        @Override
        public void remove() {
          iterator.remove();
          maintainEmptyInvariant();
        }
      };
    }

    Entry<C, V> wrapEntry(final Entry<C, V> entry) {
      return new ForwardingMapEntry<C, V>() {
        @Override
        protected Entry<C, V> delegate() {
          return entry;
        }

        @Override
        public V setValue(V value) {
          return super.setValue(checkNotNull(value));
        }

        @Override
        public boolean equals(Object object) {
          // TODO(lowasser): identify why this affects GWT tests
          return standardEquals(object);
        }
      };
    }
  }

  /**
   * {@inheritDoc}
   *
   *
The returned map's views have iterators that don't support {@code remove()}.
   */
  @Override
  public Map<R, V> column(C columnKey) {
    return new Column(columnKey);
  }

  private class Column extends ViewCachingAbstractMap<R, V> {
    final C columnKey;

    Column(C columnKey) {
      this.columnKey = checkNotNull(columnKey);
    }

    @Override
    public V put(R key, V value) {
      return StandardTable.this.put(key, columnKey, value);
    }

    @Override
    public V get(Object key) {
      return StandardTable.this.get(key, columnKey);
    }

    @Override
    public boolean containsKey(Object key) {
      return StandardTable.this.contains(key, columnKey);
    }

    @Override
    public V remove(Object key) {
      return StandardTable.this.remove(key, columnKey);
    }

    /** Removes all {@code Column} mappings whose row key and value satisfy the given predicate. */
    @CanIgnoreReturnValue
    boolean removeFromColumnIf(Predicate<? super Entry<R, V>> predicate) {
      boolean changed = false;
      Iterator<Entry<R, Map<C, V>>> iterator = backingMap.entrySet().iterator();
      while (iterator.hasNext()) {
        Entry<R, Map<C, V>> entry = iterator.next();
        Map<C, V> map = entry.getValue();
        V value = map.get(columnKey);
        if (value != null && predicate.apply(Maps.immutableEntry(entry.getKey(), value))) {
          map.remove(columnKey);
          changed = true;
          if (map.isEmpty()) {
            iterator.remove();
          }
        }
      }
      return changed;
    }

    @Override
    Set<Entry<R, V>> createEntrySet() {
      return new EntrySet();
    }

    @WeakOuter
    private class EntrySet extends ImprovedAbstractSet<Entry<R, V>> {
      @Override
      public Iterator<Entry<R, V>> iterator() {
        return new EntrySetIterator();
      }

      @Override
      public int size() {
        int size = 0;
        for (Map<C, V> map : backingMap.values()) {
          if (map.containsKey(columnKey)) {
            size++;
          }
        }
        return size;
      }

      @Override
      public boolean isEmpty() {
        return !containsColumn(columnKey);
      }

      @Override
      public void clear() {
        removeFromColumnIf(alwaysTrue());
      }

      @Override
      public boolean contains(Object o) {
        if (o instanceof Entry) {
          Entry<?, ?> entry = (Entry<?, ?>) o;
          return containsMapping(entry.getKey(), columnKey, entry.getValue());
        }
        return false;
      }

      @Override
      public boolean remove(Object obj) {
        if (obj instanceof Entry) {
          Entry<?, ?> entry = (Entry<?, ?>) obj;
          return removeMapping(entry.getKey(), columnKey, entry.getValue());
        }
        return false;
      }

      @Override
      public boolean retainAll(Collection<?> c) {
        return removeFromColumnIf(not(in(c)));
      }
    }

    private class EntrySetIterator extends AbstractIterator<Entry<R, V>> {
      final Iterator<Entry<R, Map<C, V>>> iterator = backingMap.entrySet().iterator();

      @Override
      protected Entry<R, V> computeNext() {
        while (iterator.hasNext()) {
          final Entry<R, Map<C, V>> entry = iterator.next();
          if (entry.getValue().containsKey(columnKey)) {
            @WeakOuter
            class EntryImpl extends AbstractMapEntry<R, V> {
              @Override
              public R getKey() {
                return entry.getKey();
              }

              @Override
              public V getValue() {
                return entry.getValue().get(columnKey);
              }

              @Override
              public V setValue(V value) {
                return entry.getValue().put(columnKey, checkNotNull(value));
              }
            }
            return new EntryImpl();
          }
        }
        return endOfData();
      }
    }

    @Override
    Set<R> createKeySet() {
      return new KeySet();
    }

    @WeakOuter
    private class KeySet extends Maps.KeySet<R, V> {
      KeySet() {
        super(Column.this);
      }

      @Override
      public boolean contains(Object obj) {
        return StandardTable.this.contains(obj, columnKey);
      }

      @Override
      public boolean remove(Object obj) {
        return StandardTable.this.remove(obj, columnKey) != null;
      }

      @Override
      public boolean retainAll(final Collection<?> c) {
        return removeFromColumnIf(Maps.<R>keyPredicateOnEntries(not(in(c))));
      }
    }

    @Override
    Collection<V> createValues() {
      return new Values();
    }

    @WeakOuter
    private class Values extends Maps.Values<R, V> {
      Values() {
        super(Column.this);
      }

      @Override
      public boolean remove(Object obj) {
        return obj != null && removeFromColumnIf(Maps.<V>valuePredicateOnEntries(equalTo(obj)));
      }

      @Override
      public boolean removeAll(final Collection<?> c) {
        return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(in(c)));
      }

      @Override
      public boolean retainAll(final Collection<?> c) {
        return removeFromColumnIf(Maps.<V>valuePredicateOnEntries(not(in(c))));
      }
    }
  }

  @Override
  public Set<R> rowKeySet() {
    return rowMap().keySet();
  }

  @MonotonicNonNullDecl private transient Set<C> columnKeySet;

  /**
   * {@inheritDoc}
   *
   *
The returned set has an iterator that does not support {@code remove()}.
   *
   *
The set's iterator traverses the columns of the first row, the columns of the second row,
   * etc., skipping any columns that have appeared previously.
   */
  @Override
  public Set<C> columnKeySet() {
    Set<C> result = columnKeySet;
    return (result == null) ? columnKeySet = new ColumnKeySet() : result;
  }

  @WeakOuter
  private class ColumnKeySet extends TableSet<C> {
    @Override
    public Iterator<C> iterator() {
      return createColumnKeyIterator();
    }

    @Override
    public int size() {
      return Iterators.size(iterator());
    }

    @Override
    public boolean remove(Object obj) {
      if (obj == null) {
        return false;
      }
      boolean changed = false;
      Iterator<Map<C, V>> iterator = backingMap.values().iterator();
      while (iterator.hasNext()) {
        Map<C, V> map = iterator.next();
        if (map.keySet().remove(obj)) {
          changed = true;
          if (map.isEmpty()) {
            iterator.remove();
          }
        }
      }
      return changed;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
      checkNotNull(c);
      boolean changed = false;
      Iterator<Map<C, V>> iterator = backingMap.values().iterator();
      while (iterator.hasNext()) {
        Map<C, V> map = iterator.next();
        // map.keySet().removeAll(c) can throw a NPE when map is a TreeMap with
        // natural ordering and c contains a null.
        if (Iterators.removeAll(map.keySet().iterator(), c)) {
          changed = true;
          if (map.isEmpty()) {
            iterator.remove();
          }
        }
      }
      return changed;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
      checkNotNull(c);
      boolean changed = false;
      Iterator<Map<C, V>> iterator = backingMap.values().iterator();
      while (iterator.hasNext()) {
        Map<C, V> map = iterator.next();
        if (map.keySet().retainAll(c)) {
          changed = true;
          if (map.isEmpty()) {
            iterator.remove();
          }
        }
      }
      return changed;
    }

    @Override
    public boolean contains(Object obj) {
      return containsColumn(obj);
    }
  }

  /** Creates an iterator that returns each column value with duplicates omitted. */
  Iterator<C> createColumnKeyIterator() {
    return new ColumnKeyIterator();
  }

  private class ColumnKeyIterator extends AbstractIterator<C> {
    // Use the same map type to support TreeMaps with comparators that aren't
    // consistent with equals().
    final Map<C, V> seen = factory.get();
    final Iterator<Map<C, V>> mapIterator = backingMap.values().iterator();
    Iterator<Entry<C, V>> entryIterator = Iterators.emptyIterator();

    @Override
    protected C computeNext() {
      while (true) {
        if (entryIterator.hasNext()) {
          Entry<C, V> entry = entryIterator.next();
          if (!seen.containsKey(entry.getKey())) {
            seen.put(entry.getKey(), entry.getValue());
            return entry.getKey();
          }
        } else if (mapIterator.hasNext()) {
          entryIterator = mapIterator.next().entrySet().iterator();
        } else {
          return endOfData();
        }
      }
    }
  }

  /**
   * {@inheritDoc}
   *
   *
The collection's iterator traverses the values for the first row, the values for the second
   * row, and so on.
   */
  @Override
  public Collection<V> values() {
    return super.values();
  }

  @MonotonicNonNullDecl private transient Map<R, Map<C, V>> rowMap;

  @Override
  public Map<R, Map<C, V>> rowMap() {
    Map<R, Map<C, V>> result = rowMap;
    return (result == null) ? rowMap = createRowMap() : result;
  }

  Map<R, Map<C, V>> createRowMap() {
    return new RowMap();
  }

  @WeakOuter
  class RowMap extends ViewCachingAbstractMap<R, Map<C, V>> {
    @Override
    public boolean containsKey(Object key) {
      return containsRow(key);
    }

    // performing cast only when key is in backing map and has the correct type
    @SuppressWarnings("unchecked")
    @Override
    public Map<C, V> get(Object key) {
      return containsRow(key) ? row((R) key) : null;
    }

    @Override
    public Map<C, V> remove(Object key) {
      return (key == null) ? null : backingMap.remove(key);
    }

    @Override
    protected Set<Entry<R, Map<C, V>>> createEntrySet() {
      return new EntrySet();
    }

    @WeakOuter
    class EntrySet extends TableSet<Entry<R, Map<C, V>>> {
      @Override
      public Iterator<Entry<R, Map<C, V>>> iterator() {
        return Maps.asMapEntryIterator(
            backingMap.keySet(),
            new Function<R, Map<C, V>>() {
              @Override
              public Map<C, V> apply(R rowKey) {
                return row(rowKey);
              }
            });
      }

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

      @Override
      public boolean contains(Object obj) {
        if (obj instanceof Entry) {
          Entry<?, ?> entry = (Entry<?, ?>) obj;
          return entry.getKey() != null
              && entry.getValue() instanceof Map
              && Collections2.safeContains(backingMap.entrySet(), entry);
        }
        return false;
      }

      @Override
      public boolean remove(Object obj) {
        if (obj instanceof Entry) {
          Entry<?, ?> entry = (Entry<?, ?>) obj;
          return entry.getKey() != null
              && entry.getValue() instanceof Map
              && backingMap.entrySet().remove(entry);
        }
        return false;
      }
    }
  }

  @MonotonicNonNullDecl private transient ColumnMap columnMap;

  @Override
  public Map<C, Map<R, V>> columnMap() {
    ColumnMap result = columnMap;
    return (result == null) ? columnMap = new ColumnMap() : result;
  }

  @WeakOuter
  private class ColumnMap extends ViewCachingAbstractMap<C, Map<R, V>> {
    // The cast to C occurs only when the key is in the map, implying that it
    // has the correct type.
    @SuppressWarnings("unchecked")
    @Override
    public Map<R, V> get(Object key) {
      return containsColumn(key) ? column((C) key) : null;
    }

    @Override
    public boolean containsKey(Object key) {
      return containsColumn(key);
    }

    @Override
    public Map<R, V> remove(Object key) {
      return containsColumn(key) ? removeColumn(key) : null;
    }

    @Override
    public Set<Entry<C, Map<R, V>>> createEntrySet() {
      return new ColumnMapEntrySet();
    }

    @Override
    public Set<C> keySet() {
      return columnKeySet();
    }

    @Override
    Collection<Map<R, V>> createValues() {
      return new ColumnMapValues();
    }

    @WeakOuter
    class ColumnMapEntrySet extends TableSet<Entry<C, Map<R, V>>> {
      @Override
      public Iterator<Entry<C, Map<R, V>>> iterator() {
        return Maps.asMapEntryIterator(
            columnKeySet(),
            new Function<C, Map<R, V>>() {
              @Override
              public Map<R, V> apply(C columnKey) {
                return column(columnKey);
              }
            });
      }

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

      @Override
      public boolean contains(Object obj) {
        if (obj instanceof Entry) {
          Entry<?, ?> entry = (Entry<?, ?>) obj;
          if (containsColumn(entry.getKey())) {
            // The cast to C occurs only when the key is in the map, implying
            // that it has the correct type.
            @SuppressWarnings("unchecked")
            C columnKey = (C) entry.getKey();
            return get(columnKey).equals(entry.getValue());
          }
        }
        return false;
      }

      @Override
      public boolean remove(Object obj) {
        if (contains(obj)) {
          Entry<?, ?> entry = (Entry<?, ?>) obj;
          removeColumn(entry.getKey());
          return true;
        }
        return false;
      }

      @Override
      public boolean removeAll(Collection<?> c) {
        /*
         * We can't inherit the normal implementation (which calls
         * Sets.removeAllImpl(Set, *Collection*) because, under some
         * circumstances, it attempts to call columnKeySet().iterator().remove,
         * which is unsupported.
         */
        checkNotNull(c);
        return Sets.removeAllImpl(this, c.iterator());
      }

      @Override
      public boolean retainAll(Collection<?> c) {
        checkNotNull(c);
        boolean changed = false;
        for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
          if (!c.contains(Maps.immutableEntry(columnKey, column(columnKey)))) {
            removeColumn(columnKey);
            changed = true;
          }
        }
        return changed;
      }
    }

    @WeakOuter
    private class ColumnMapValues extends Maps.Values<C, Map<R, V>> {
      ColumnMapValues() {
        super(ColumnMap.this);
      }

      @Override
      public boolean remove(Object obj) {
        for (Entry<C, Map<R, V>> entry : ColumnMap.this.entrySet()) {
          if (entry.getValue().equals(obj)) {
            removeColumn(entry.getKey());
            return true;
          }
        }
        return false;
      }

      @Override
      public boolean removeAll(Collection<?> c) {
        checkNotNull(c);
        boolean changed = false;
        for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
          if (c.contains(column(columnKey))) {
            removeColumn(columnKey);
            changed = true;
          }
        }
        return changed;
      }

      @Override
      public boolean retainAll(Collection<?> c) {
        checkNotNull(c);
        boolean changed = false;
        for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
          if (!c.contains(column(columnKey))) {
            removeColumn(columnKey);
            changed = true;
          }
        }
        return changed;
      }
    }
  }

  private static final long serialVersionUID = 0;
}