/* * 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 type of the vector. */ public abstract class VectorValueComparator { /** * 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 createNew(); }