content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to you 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 org.apache.calcite.runtime;
  
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableMap;
  import com.google.common.collect.Lists;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.List;
  import java.util.Map;
  import java.util.function.BiConsumer;
  import java.util.function.BiFunction;
  import java.util.function.BiPredicate;
  
  import static com.google.common.base.Preconditions.checkArgument;
  
  import static org.apache.calcite.linq4j.Nullness.castNonNullList;
  
  /** A list of pairs, stored as a quotient list.
   *
   * @param <T> First type
   * @param <U> Second type
   */
  public interface PairList<T, U> extends List<Map.Entry<T, U>> {
    /** Creates an empty PairList. */
    static <T, U> PairList<T, U> of() {
      return new PairLists.MutablePairList<>(new ArrayList<>());
    }
  
    /** Creates a singleton PairList. */
    @SuppressWarnings("RedundantCast")
    static <T, U> PairList<T, U> of(T t, U u) {
      final List<@Nullable Object> list = new ArrayList<>();
      list.add((Object) t);
      list.add((Object) u);
      return new PairLists.MutablePairList<>(list);
    }
  
    /** Creates a PairList with one or more entries. */
    static <T, U> PairList<T, U> copyOf(T t, U u, Object... rest) {
      checkArgument(rest.length % 2 == 0, "even number");
      final List<@Nullable Object> list = Lists.asList(t, u, rest);
      return new PairLists.MutablePairList<>(new ArrayList<>(list));
    }
  
    /** Creates an empty PairList with a specified initial capacity. */
    static <T, U> PairList<T, U> withCapacity(int initialCapacity) {
      return backedBy(new ArrayList<>(initialCapacity));
    }
  
    /** Creates a PairList backed by a given list.
     *
     * <p>Changes to the backing list will be reflected in the PairList.
     * If the backing list is immutable, this PairList will be also. */
    static <T, U> PairList<T, U> backedBy(List<@Nullable Object> list) {
      return new PairLists.MutablePairList<>(list);
    }
  
    /** Creates a PairList from a Map. */
    @SuppressWarnings("RedundantCast")
    static <T, U> PairList<T, U> of(Map<T, U> map) {
      final List<@Nullable Object> list = new ArrayList<>(map.size() * 2);
      map.forEach((t, u) -> {
        list.add((Object) t);
        list.add((Object) u);
      });
      return new PairLists.MutablePairList<>(list);
    }
  
    /** Creates a Builder. */
    static <T, U> Builder<T, U> builder() {
      return new Builder<>();
    }
  
    /** Adds a pair to this list. */
    default void add(T t, U u) {
      throw new UnsupportedOperationException("add");
    }
  
    /** Adds a pair to this list at a given position. */
    default void add(int index, T t, U u) {
      throw new UnsupportedOperationException("add");
    }
  
    /** Adds to this list the contents of another PairList.
     *
     * <p>Equivalent to {@link #addAll(Collection)}, but more efficient. */
    default boolean addAll(PairList<T, U> list2) {
      throw new UnsupportedOperationException("addAll");
    }
  
    /** Adds to this list, at a given index, the contents of another PairList.
     *
     * <p>Equivalent to {@link #addAll(int, Collection)}, but more efficient. */
    default boolean addAll(int index, PairList<T, U> list2) {
      throw new UnsupportedOperationException("addAll");
    }
  
    /** Sets the entry at position {@code index} to the pair {@code (t, u)}. */
    default Map.Entry<T, U> set(int index, T t, U u) {
      throw new UnsupportedOperationException("set");
    }
  
    @Override default Map.Entry<T, U> remove(int index) {
      throw new UnsupportedOperationException("remove");
    }
  
    /** Returns the left part of the {@code index}th pair. */
    T left(int index);
  
    /** Returns the right part of the {@code index}th pair. */
    U right(int index);
  
    /** Returns an unmodifiable list view consisting of the left entry of each
     * pair. */
    List<T> leftList();
  
    /** Returns an unmodifiable list view consisting of the right entry of each
     * pair. */
    List<U> rightList();
  
    /** Calls a BiConsumer with each pair in this list. */
    void forEach(BiConsumer<T, U> consumer);
  
    /** Calls a BiConsumer with each pair in this list. */
    void forEachIndexed(IndexedBiConsumer<T, U> consumer);
  
    /** Creates an {@link ImmutableMap} whose entries are the pairs in this list.
     * Throws if keys are not unique. */
    default ImmutableMap<T, U> toImmutableMap() {
      final ImmutableMap.Builder<T, U> b = ImmutableMap.builder();
      forEach((t, u) -> b.put(t, u));
      return b.build();
    }
  
    /** Returns an ImmutablePairList whose contents are the same as this
     * PairList. */
    ImmutablePairList<T, U> immutable();
  
    /** Applies a mapping function to each element of this list. */
    <R> List<R> transform(BiFunction<T, U, R> function);
  
    /** Applies a mapping function to each element of this list. */
    <R> ImmutableList<R> transform2(BiFunction<T, U, R> function);
  
    @Override PairList<T, U> subList(int fromIndex, int toIndex);
  
    /** Returns whether the predicate is true for at least one pair
     * in this list. */
    boolean anyMatch(BiPredicate<T, U> predicate);
  
    /** Returns whether the predicate is true for all pairs
     * in this list. */
    boolean allMatch(BiPredicate<T, U> predicate);
  
    /** Returns whether the predicate is true for no pairs
     * in this list. */
    boolean noMatch(BiPredicate<T, U> predicate);
  
    /** Reverses the contents of this PairList.
     * Throws if this PairList is immutable.
     *
     * @see #reversed() */
    default void reverse() {
      throw new UnsupportedOperationException("reverse");
    }
  
    /** Returns an immutable copy of this ImmutablePairList with the elements
     * reversed.
     *
     * <p>Throws {@link NullPointerException} if any keys or values are null. */
    ImmutablePairList<T, U> reversed();
  
    /** Action to be taken each step of an indexed iteration over a PairList.
     *
     * @param <T> First type
     * @param <U> Second type
     *
     * @see PairList#forEachIndexed(IndexedBiConsumer)
     */
    interface IndexedBiConsumer<T, U> {
      /**
       * Performs this operation on the given arguments.
       *
       * @param index Index
       * @param t First input argument
       * @param u Second input argument
       */
      void accept(int index, T t, U u);
    }
  
    /** Builds a PairList.
     *
     * @param <T> First type
     * @param <U> Second type */
    class Builder<T, U> {
      final List<@Nullable Object> list = new ArrayList<>();
  
      /** Adds a pair to the list under construction. */
      @SuppressWarnings("RedundantCast")
      public Builder<T, U> add(T t, U u) {
        list.add((Object) t);
        list.add((Object) u);
        return this;
      }
  
      /** Builds the PairList. */
      public PairList<T, U> build() {
        return new PairLists.MutablePairList<>(list);
      }
  
      /** Builds an ImmutablePairList. */
      public ImmutablePairList<T, U> buildImmutable() {
        return PairLists.immutableBackedBy(castNonNullList(list));
      }
    }
  
    /** For code invoked via Janino, which cannot call static methods
     * in interfaces. */
    @Deprecated
    class Helper {
      private Helper() {}
  
      public static <T, U> PairList<T, U> copyOf(T t, U u, Object... rest) {
        return PairList.copyOf(t, u, rest);
      }
    }
  }
  