| /* |
| * 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); |
| } |
| } |
| |
| } |