blob: 4ac6ed1311ab9ffce2d67138961ecb92fbd41318 [file] [log] [blame]
/*
* 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.lucene.util;
import java.util.Arrays;
/**
* A LSB Radix sorter for unsigned int values.
* @lucene.internal
*/
public final class LSBRadixSorter {
private static final int INSERTION_SORT_THRESHOLD = 30;
private static final int HISTOGRAM_SIZE = 256;
private final int[] histogram = new int[HISTOGRAM_SIZE];
private int[] buffer = new int[0];
private static void buildHistogram(int[] array, int len, int[] histogram, int shift) {
for (int i = 0; i < len; ++i) {
final int b = (array[i] >>> shift) & 0xFF;
histogram[b] += 1;
}
}
private static void sumHistogram(int[] histogram) {
int accum = 0;
for (int i = 0; i < HISTOGRAM_SIZE; ++i) {
final int count = histogram[i];
histogram[i] = accum;
accum += count;
}
}
private static void reorder(int[] array, int len, int[] histogram, int shift, int[] dest) {
for (int i = 0; i < len; ++i) {
final int v = array[i];
final int b = (v >>> shift) & 0xFF;
dest[histogram[b]++] = v;
}
}
private static boolean sort(int[] array, int len, int[] histogram, int shift, int[] dest) {
Arrays.fill(histogram, 0);
buildHistogram(array, len, histogram, shift);
if (histogram[0] == len) {
return false;
}
sumHistogram(histogram);
reorder(array, len, histogram, shift, dest);
return true;
}
private static void insertionSort(int[] array, int off, int len) {
for (int i = off + 1, end = off + len; i < end; ++i) {
for (int j = i; j > off; --j) {
if (array[j - 1] > array[j]) {
int tmp = array[j - 1];
array[j - 1] = array[j];
array[j] = tmp;
} else {
break;
}
}
}
}
/** Sort {@code array[0:len]} in place.
* @param numBits how many bits are required to store any of the values in
* {@code array[0:len]}. Pass {@code 32} if unknown. */
public void sort(int numBits, final int[] array, int len) {
if (len < INSERTION_SORT_THRESHOLD) {
insertionSort(array, 0, len);
return;
}
buffer = ArrayUtil.grow(buffer, len);
int[] arr = array;
int[] buf = buffer;
for (int shift = 0; shift < numBits; shift += 8) {
if (sort(arr, len, histogram, shift, buf)) {
// swap arrays
int[] tmp = arr;
arr = buf;
buf = tmp;
}
}
if (array == buf) {
System.arraycopy(arr, 0, array, 0, len);
}
}
}