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.rel;
  
  import org.apache.calcite.plan.RelMultipleTrait;
  import org.apache.calcite.plan.RelOptPlanner;
  import org.apache.calcite.plan.RelTrait;
  import org.apache.calcite.plan.RelTraitDef;
  import org.apache.calcite.rel.type.RelDataType;
  import org.apache.calcite.rex.RexUtil;
  import org.apache.calcite.runtime.Utilities;
  import org.apache.calcite.util.Util;
  import org.apache.calcite.util.mapping.Mappings;
  
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.UnmodifiableIterator;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  
  import java.util.Iterator;
  import java.util.List;
  
  import static com.google.common.base.Preconditions.checkArgument;
  
  /**
   * Simple implementation of {@link RelCollation}.
   */
  public class RelCollationImpl implements RelCollation {
    //~ Static fields/initializers ---------------------------------------------
  
    @Deprecated // to be removed before 2.0
    public static final RelCollation EMPTY = RelCollations.EMPTY;
  
    @Deprecated // to be removed before 2.0
    public static final RelCollation PRESERVE = RelCollations.PRESERVE;
  
    //~ Instance fields --------------------------------------------------------
  
    private final ImmutableList<RelFieldCollation> fieldCollations;
  
    //~ Constructors -----------------------------------------------------------
  
    protected RelCollationImpl(ImmutableList<RelFieldCollation> fieldCollations) {
      this.fieldCollations = fieldCollations;
      checkArgument(Util.isDistinct(RelCollations.ordinals(fieldCollations)),
          "fields must be distinct");
    }
  
    @Deprecated // to be removed before 2.0
    public static RelCollation of(RelFieldCollation... fieldCollations) {
      return RelCollations.of(fieldCollations);
    }
  
    @Deprecated // to be removed before 2.0
    public static RelCollation of(List<RelFieldCollation> fieldCollations) {
      return RelCollations.of(fieldCollations);
    }
  
    //~ Methods ----------------------------------------------------------------
  
    @Override public RelTraitDef getTraitDef() {
      return RelCollationTraitDef.INSTANCE;
    }
  
    @Override public List<RelFieldCollation> getFieldCollations() {
      return fieldCollations;
    }
  
    @Override public int hashCode() {
      return fieldCollations.hashCode();
    }
  
    @Override public boolean equals(@Nullable Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj instanceof RelCollationImpl) {
        RelCollationImpl that = (RelCollationImpl) obj;
        return this.fieldCollations.equals(that.fieldCollations);
      }
      return false;
    }
  
    @Override public boolean isTop() {
      return fieldCollations.isEmpty();
    }
  
    @Override public int compareTo(RelMultipleTrait o) {
      final RelCollationImpl that = (RelCollationImpl) o;
      final UnmodifiableIterator<RelFieldCollation> iterator =
          that.fieldCollations.iterator();
      for (RelFieldCollation f : fieldCollations) {
        if (!iterator.hasNext()) {
          return 1;
        }
        final RelFieldCollation f2 = iterator.next();
        int c = Utilities.compare(f.getFieldIndex(), f2.getFieldIndex());
        if (c != 0) {
          return c;
        }
      }
      return iterator.hasNext() ? -1 : 0;
    }
  
    @Override public void register(RelOptPlanner planner) {}
  
    /**
     * Applies mapping to a given collation.
     *
     * <p>If mapping destroys the collation prefix, this method returns an empty
     * collation.  Examples of applying mappings to collation [0, 1]:
     *
     * <ul>
     *   <li>mapping(0, 1) =&gt; [0, 1]</li>
     *   <li>mapping(1, 0) =&gt; [1, 0]</li>
     *   <li>mapping(0) =&gt; [0]</li>
     *   <li>mapping(1) =&gt; []</li>
     *   <li>mapping(2, 0) =&gt; [1]</li>
     *   <li>mapping(2, 1, 0) =&gt; [2, 1]</li>
     *   <li>mapping(2, 1) =&gt; []</li>
     * </ul>
     *
     * @param mapping   Mapping
     * @return Collation with applied mapping.
     */
    @Override public RelCollationImpl apply(
        final Mappings.TargetMapping mapping) {
      return (RelCollationImpl) RexUtil.apply(mapping, this);
    }
  
    @Override public boolean satisfies(RelTrait trait) {
      return this == trait
          || trait instanceof RelCollationImpl
          && Util.startsWith(fieldCollations,
              ((RelCollationImpl) trait).fieldCollations);
    }
  
    /** Returns a string representation of this collation, suitably terse given
     * that it will appear in plan traces. Examples:
     * "[]", "[2]", "[0 DESC, 1]", "[0 DESC, 1 ASC NULLS LAST]". */
    @Override public String toString() {
      Iterator<RelFieldCollation> it = fieldCollations.iterator();
      if (! it.hasNext()) {
        return "[]";
      }
      StringBuilder sb = new StringBuilder();
      sb.append('[');
      for (;;) {
        RelFieldCollation e = it.next();
        sb.append(e.getFieldIndex());
        if (e.direction != RelFieldCollation.Direction.ASCENDING
            || e.nullDirection != e.direction.defaultNullDirection()) {
          sb.append(' ').append(e.shortString());
        }
        if (!it.hasNext()) {
          return sb.append(']').toString();
        }
        sb.append(',').append(' ');
      }
    }
  
    @Deprecated // to be removed before 2.0
    public static List<RelCollation> createSingleton(int fieldIndex) {
      return RelCollations.createSingleton(fieldIndex);
    }
  
    @Deprecated // to be removed before 2.0
    public static boolean isValid(
        RelDataType rowType,
        List<RelCollation> collationList,
        boolean fail) {
      return RelCollations.isValid(rowType, collationList, fail);
    }
  
    @Deprecated // to be removed before 2.0
    public static boolean equal(
        List<RelCollation> collationList1,
        List<RelCollation> collationList2) {
      return RelCollations.equal(collationList1, collationList2);
    }
  
    @Deprecated // to be removed before 2.0
    public static List<Integer> ordinals(RelCollation collation) {
      return RelCollations.ordinals(collation);
    }
  }
  