io.trino.operator.PagesIndexOrdering Maven / Gradle / Ivy
/*
* 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 io.trino.operator;
import static java.util.Objects.requireNonNull;
public class PagesIndexOrdering
{
private static final int SMALL = 7;
private static final int MEDIUM = 40;
private final PagesIndexComparator comparator;
public PagesIndexOrdering(PagesIndexComparator comparator)
{
this.comparator = requireNonNull(comparator, "comparator is null");
}
public PagesIndexComparator getComparator()
{
return comparator;
}
public void sort(PagesIndex pagesIndex, int startPosition, int endPosition)
{
quickSort(pagesIndex, startPosition, endPosition);
}
/**
* Sorts the specified range of elements using the specified swapper and according to the order induced by the specified
* comparator using quickSort.
*
* The sorting algorithm is a tuned quickSort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
// note this code was forked from Fastutils
@SuppressWarnings("InnerAssignment")
private void quickSort(PagesIndex pagesIndex, int from, int to)
{
int len = to - from;
// Insertion sort on smallest arrays
if (len < SMALL) {
for (int i = from; i < to; i++) {
for (int j = i; j > from && (comparator.compareTo(pagesIndex, j - 1, j) > 0); j--) {
pagesIndex.swap(j, j - 1);
}
}
return;
}
// Choose a partition element, v
int m = from + len / 2; // Small arrays, middle element
if (len > SMALL) {
int l = from;
int n = to - 1;
if (len > MEDIUM) { // Big arrays, pseudomedian of 9
int s = len / 8;
l = median3(pagesIndex, l, l + s, l + 2 * s);
m = median3(pagesIndex, m - s, m, m + s);
n = median3(pagesIndex, n - 2 * s, n - s, n);
}
m = median3(pagesIndex, l, m, n); // Mid-size, med of 3
}
// int v = x[m];
int a = from;
int b = a;
int c = to - 1;
// Establish Invariant: v* (v)* v*
int d = c;
while (true) {
int comparison;
while (b <= c && ((comparison = comparator.compareTo(pagesIndex, b, m)) <= 0)) {
if (comparison == 0) {
if (a == m) {
m = b; // moving target; DELTA to JDK !!!
}
else if (b == m) {
m = a; // moving target; DELTA to JDK !!!
}
pagesIndex.swap(a++, b);
}
b++;
}
while (c >= b && ((comparison = comparator.compareTo(pagesIndex, c, m)) >= 0)) {
if (comparison == 0) {
if (c == m) {
m = d; // moving target; DELTA to JDK !!!
}
else if (d == m) {
m = c; // moving target; DELTA to JDK !!!
}
pagesIndex.swap(c, d--);
}
c--;
}
if (b > c) {
break;
}
if (b == m) {
m = d; // moving target; DELTA to JDK !!!
}
else if (c == m) {
m = c; // moving target; DELTA to JDK !!!
}
pagesIndex.swap(b++, c--);
}
// Swap partition elements back to middle
int s;
int n = to;
s = Math.min(a - from, b - a);
vectorSwap(pagesIndex, from, b - s, s);
s = Math.min(d - c, n - d - 1);
vectorSwap(pagesIndex, b, n - s, s);
// Recursively sort non-partition-elements
if ((s = b - a) > 1) {
quickSort(pagesIndex, from, from + s);
}
if ((s = d - c) > 1) {
quickSort(pagesIndex, n - s, n);
}
}
/**
* Returns the index of the median of the three positions.
*/
private int median3(PagesIndex pagesIndex, int a, int b, int c)
{
int ab = comparator.compareTo(pagesIndex, a, b);
int ac = comparator.compareTo(pagesIndex, a, c);
int bc = comparator.compareTo(pagesIndex, b, c);
return (ab < 0 ?
(bc < 0 ? b : ac < 0 ? c : a) :
(bc > 0 ? b : ac > 0 ? c : a));
}
/**
* Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
*/
private static void vectorSwap(PagesIndex pagesIndex, int from, int l, int s)
{
for (int i = 0; i < s; i++, from++, l++) {
pagesIndex.swap(from, l);
}
}
}