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.arrow.algorithm.sort;
  
  import org.apache.arrow.vector.ValueVector;
  
  /**
   * Compare two values at the given indices in the vectors. This is used for vector sorting.
   *
   * @param <V> type of the vector.
   */
  public abstract class VectorValueComparator<V extends ValueVector> {
  
    /** The first vector to compare. */
    protected V vector1;
  
    /** The second vector to compare. */
    protected V vector2;
  
    /** Width of the vector value. For variable-length vectors, this value makes no sense. */
    protected int valueWidth;
  
    private boolean checkNullsOnCompare = true;
  
    /**
     * This value is true by default and re-computed when vectors are attached to the comparator. If
     * both vectors cannot contain nulls then this value is {@code false} and calls to {@code
     * compare(i1, i2)} are short-circuited to {@code compareNotNull(i1, i2)} thereby speeding up
     * comparisons resulting in faster sorts etc.
     */
    public boolean checkNullsOnCompare() {
      return this.checkNullsOnCompare;
    }
  
    /** Constructor for variable-width vectors. */
    protected VectorValueComparator() {}
  
    /**
     * Constructor for fixed-width vectors.
     *
     * @param valueWidth the record width (in bytes).
     */
    protected VectorValueComparator(int valueWidth) {
      this.valueWidth = valueWidth;
    }
  
    public int getValueWidth() {
      return valueWidth;
    }
  
    /**
     * Attach both vectors to compare to the same input vector.
     *
     * @param vector the vector to attach.
     */
    public void attachVector(V vector) {
      attachVectors(vector, vector);
    }
  
    /**
     * Attach vectors to compare.
     *
     * @param vector1 the first vector to compare.
     * @param vector2 the second vector to compare.
     */
    public void attachVectors(V vector1, V vector2) {
      this.vector1 = vector1;
      this.vector2 = vector2;
  
      final boolean v1MayHaveNulls = mayHaveNulls(vector1);
      final boolean v2MayHaveNulls = mayHaveNulls(vector2);
  
      this.checkNullsOnCompare = v1MayHaveNulls || v2MayHaveNulls;
    }
  
    private boolean mayHaveNulls(V v) {
      if (v.getValueCount() == 0) {
        return true;
      }
      if (!v.getField().isNullable()) {
        return false;
      }
      return v.getNullCount() > 0;
    }
  
    /**
     * Compare two values, given their indices.
     *
     * @param index1 index of the first value to compare.
     * @param index2 index of the second value to compare.
     * @return an integer greater than 0, if the first value is greater; an integer smaller than 0, if
     *     the first value is smaller; or 0, if both values are equal.
     */
    public int compare(int index1, int index2) {
      if (checkNullsOnCompare) {
        boolean isNull1 = vector1.isNull(index1);
        boolean isNull2 = vector2.isNull(index2);
  
        if (isNull1 || isNull2) {
          if (isNull1 && isNull2) {
            return 0;
          } else if (isNull1) {
            // null is smaller
            return -1;
          } else {
            return 1;
          }
        }
      }
      return compareNotNull(index1, index2);
    }
  
    /**
     * Compare two values, given their indices. This is a fast path for comparing non-null values, so
     * the caller must make sure that values at both indices are not null.
     *
     * @param index1 index of the first value to compare.
     * @param index2 index of the second value to compare.
     * @return an integer greater than 0, if the first value is greater; an integer smaller than 0, if
     *     the first value is smaller; or 0, if both values are equal.
     */
    public abstract int compareNotNull(int index1, int index2);
  
    /**
     * Creates a comparator of the same type.
     *
     * @return the newly created comparator.
     */
    public abstract VectorValueComparator<V> createNew();
  }
  