1 package org.apache.lucene.util;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.util.Collection;
21 import java.util.Comparator;
24 * Methods for manipulating arrays.
28 public final class ArrayUtil {
31 * @deprecated This constructor was not intended to be public and should not be used.
32 * This class contains solely a static utility methods.
33 * It will be made private in Lucene 4.0
35 // make private in 4.0!
37 public ArrayUtil() {} // no instance
40 Begin Apache Harmony code
42 Revision taken on Friday, June 12. https://svn.apache.org/repos/asf/harmony/enhanced/classlib/archive/java6/modules/luni/src/main/java/java/lang/Integer.java
47 * Parses the string argument as if it was an int value and returns the
48 * result. Throws NumberFormatException if the string does not represent an
51 * @param chars a string representation of an int quantity.
52 * @return int the value represented by the argument
53 * @throws NumberFormatException if the argument could not be parsed as an int quantity.
55 public static int parseInt(char[] chars) throws NumberFormatException {
56 return parseInt(chars, 0, chars.length, 10);
60 * Parses a char array into an int.
61 * @param chars the character array
62 * @param offset The offset into the array
63 * @param len The length
65 * @throws NumberFormatException if it can't parse
67 public static int parseInt(char[] chars, int offset, int len) throws NumberFormatException {
68 return parseInt(chars, offset, len, 10);
72 * Parses the string argument as if it was an int value and returns the
73 * result. Throws NumberFormatException if the string does not represent an
74 * int quantity. The second argument specifies the radix to use when parsing
77 * @param chars a string representation of an int quantity.
78 * @param radix the base to use for conversion.
79 * @return int the value represented by the argument
80 * @throws NumberFormatException if the argument could not be parsed as an int quantity.
82 public static int parseInt(char[] chars, int offset, int len, int radix)
83 throws NumberFormatException {
84 if (chars == null || radix < Character.MIN_RADIX
85 || radix > Character.MAX_RADIX) {
86 throw new NumberFormatException();
90 throw new NumberFormatException("chars length is 0");
92 boolean negative = chars[offset + i] == '-';
93 if (negative && ++i == len) {
94 throw new NumberFormatException("can't convert to an int");
96 if (negative == true){
100 return parse(chars, offset, len, radix, negative);
104 private static int parse(char[] chars, int offset, int len, int radix,
105 boolean negative) throws NumberFormatException {
106 int max = Integer.MIN_VALUE / radix;
108 for (int i = 0; i < len; i++){
109 int digit = Character.digit(chars[i + offset], radix);
111 throw new NumberFormatException("Unable to parse");
114 throw new NumberFormatException("Unable to parse");
116 int next = result * radix - digit;
118 throw new NumberFormatException("Unable to parse");
122 /*while (offset < len) {
128 throw new NumberFormatException("Unable to parse");
137 END APACHE HARMONY CODE
140 /** Returns an array size >= minTargetSize, generally
141 * over-allocating exponentially to achieve amortized
142 * linear-time cost as the array grows.
144 * NOTE: this was originally borrowed from Python 2.4.2
145 * listobject.c sources (attribution in LICENSE.txt), but
146 * has now been substantially changed based on
147 * discussions from java-dev thread with subject "Dynamic
148 * array reallocation algorithms", started on Jan 12
151 * @param minTargetSize Minimum required value to be returned.
152 * @param bytesPerElement Bytes used by each element of
153 * the array. See constants in {@link RamUsageEstimator}.
158 public static int oversize(int minTargetSize, int bytesPerElement) {
160 if (minTargetSize < 0) {
161 // catch usage that accidentally overflows int
162 throw new IllegalArgumentException("invalid array size " + minTargetSize);
165 if (minTargetSize == 0) {
166 // wait until at least one element is requested
170 // asymptotic exponential growth by 1/8th, favors
171 // spending a bit more CPU to not tie up too much wasted
173 int extra = minTargetSize >> 3;
176 // for very small arrays, where constant overhead of
177 // realloc is presumably relatively high, we grow
182 int newSize = minTargetSize + extra;
184 // add 7 to allow for worst case byte alignment addition below:
186 // int overflowed -- return max allowed array size
187 return Integer.MAX_VALUE;
190 if (Constants.JRE_IS_64BIT) {
191 // round up to 8 byte alignment in 64bit env
192 switch(bytesPerElement) {
194 // round up to multiple of 2
195 return (newSize + 1) & 0x7ffffffe;
197 // round up to multiple of 4
198 return (newSize + 3) & 0x7ffffffc;
200 // round up to multiple of 8
201 return (newSize + 7) & 0x7ffffff8;
205 // odd (invalid?) size
209 // round up to 4 byte alignment in 64bit env
210 switch(bytesPerElement) {
212 // round up to multiple of 2
213 return (newSize + 1) & 0x7ffffffe;
215 // round up to multiple of 4
216 return (newSize + 3) & 0x7ffffffc;
221 // odd (invalid?) size
227 public static int getShrinkSize(int currentSize, int targetSize, int bytesPerElement) {
228 final int newSize = oversize(targetSize, bytesPerElement);
229 // Only reallocate if we are "substantially" smaller.
230 // This saves us from "running hot" (constantly making a
231 // bit bigger then a bit smaller, over and over):
232 if (newSize < currentSize / 2)
238 public static short[] grow(short[] array, int minSize) {
239 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
240 if (array.length < minSize) {
241 short[] newArray = new short[oversize(minSize, RamUsageEstimator.NUM_BYTES_SHORT)];
242 System.arraycopy(array, 0, newArray, 0, array.length);
248 public static short[] grow(short[] array) {
249 return grow(array, 1 + array.length);
252 public static float[] grow(float[] array, int minSize) {
253 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
254 if (array.length < minSize) {
255 float[] newArray = new float[oversize(minSize, RamUsageEstimator.NUM_BYTES_FLOAT)];
256 System.arraycopy(array, 0, newArray, 0, array.length);
262 public static float[] grow(float[] array) {
263 return grow(array, 1 + array.length);
266 public static double[] grow(double[] array, int minSize) {
267 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
268 if (array.length < minSize) {
269 double[] newArray = new double[oversize(minSize, RamUsageEstimator.NUM_BYTES_DOUBLE)];
270 System.arraycopy(array, 0, newArray, 0, array.length);
276 public static double[] grow(double[] array) {
277 return grow(array, 1 + array.length);
280 public static short[] shrink(short[] array, int targetSize) {
281 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
282 final int newSize = getShrinkSize(array.length, targetSize, RamUsageEstimator.NUM_BYTES_SHORT);
283 if (newSize != array.length) {
284 short[] newArray = new short[newSize];
285 System.arraycopy(array, 0, newArray, 0, newSize);
291 public static int[] grow(int[] array, int minSize) {
292 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
293 if (array.length < minSize) {
294 int[] newArray = new int[oversize(minSize, RamUsageEstimator.NUM_BYTES_INT)];
295 System.arraycopy(array, 0, newArray, 0, array.length);
301 public static int[] grow(int[] array) {
302 return grow(array, 1 + array.length);
305 public static int[] shrink(int[] array, int targetSize) {
306 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
307 final int newSize = getShrinkSize(array.length, targetSize, RamUsageEstimator.NUM_BYTES_INT);
308 if (newSize != array.length) {
309 int[] newArray = new int[newSize];
310 System.arraycopy(array, 0, newArray, 0, newSize);
316 public static long[] grow(long[] array, int minSize) {
317 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
318 if (array.length < minSize) {
319 long[] newArray = new long[oversize(minSize, RamUsageEstimator.NUM_BYTES_LONG)];
320 System.arraycopy(array, 0, newArray, 0, array.length);
326 public static long[] grow(long[] array) {
327 return grow(array, 1 + array.length);
330 public static long[] shrink(long[] array, int targetSize) {
331 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
332 final int newSize = getShrinkSize(array.length, targetSize, RamUsageEstimator.NUM_BYTES_LONG);
333 if (newSize != array.length) {
334 long[] newArray = new long[newSize];
335 System.arraycopy(array, 0, newArray, 0, newSize);
341 public static byte[] grow(byte[] array, int minSize) {
342 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
343 if (array.length < minSize) {
344 byte[] newArray = new byte[oversize(minSize, 1)];
345 System.arraycopy(array, 0, newArray, 0, array.length);
351 public static byte[] grow(byte[] array) {
352 return grow(array, 1 + array.length);
355 public static byte[] shrink(byte[] array, int targetSize) {
356 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
357 final int newSize = getShrinkSize(array.length, targetSize, 1);
358 if (newSize != array.length) {
359 byte[] newArray = new byte[newSize];
360 System.arraycopy(array, 0, newArray, 0, newSize);
366 public static boolean[] grow(boolean[] array, int minSize) {
367 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
368 if (array.length < minSize) {
369 boolean[] newArray = new boolean[oversize(minSize, 1)];
370 System.arraycopy(array, 0, newArray, 0, array.length);
376 public static boolean[] grow(boolean[] array) {
377 return grow(array, 1 + array.length);
380 public static boolean[] shrink(boolean[] array, int targetSize) {
381 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
382 final int newSize = getShrinkSize(array.length, targetSize, 1);
383 if (newSize != array.length) {
384 boolean[] newArray = new boolean[newSize];
385 System.arraycopy(array, 0, newArray, 0, newSize);
391 public static char[] grow(char[] array, int minSize) {
392 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
393 if (array.length < minSize) {
394 char[] newArray = new char[oversize(minSize, RamUsageEstimator.NUM_BYTES_CHAR)];
395 System.arraycopy(array, 0, newArray, 0, array.length);
401 public static char[] grow(char[] array) {
402 return grow(array, 1 + array.length);
405 public static char[] shrink(char[] array, int targetSize) {
406 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
407 final int newSize = getShrinkSize(array.length, targetSize, RamUsageEstimator.NUM_BYTES_CHAR);
408 if (newSize != array.length) {
409 char[] newArray = new char[newSize];
410 System.arraycopy(array, 0, newArray, 0, newSize);
416 public static int[][] grow(int[][] array, int minSize) {
417 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
418 if (array.length < minSize) {
419 int[][] newArray = new int[oversize(minSize, RamUsageEstimator.NUM_BYTES_OBJECT_REF)][];
420 System.arraycopy(array, 0, newArray, 0, array.length);
427 public static int[][] grow(int[][] array) {
428 return grow(array, 1 + array.length);
431 public static int[][] shrink(int[][] array, int targetSize) {
432 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
433 final int newSize = getShrinkSize(array.length, targetSize, RamUsageEstimator.NUM_BYTES_OBJECT_REF);
434 if (newSize != array.length) {
435 int[][] newArray = new int[newSize][];
436 System.arraycopy(array, 0, newArray, 0, newSize);
443 public static float[][] grow(float[][] array, int minSize) {
444 assert minSize >= 0: "size must be positive (got " + minSize + "): likely integer overflow?";
445 if (array.length < minSize) {
446 float[][] newArray = new float[oversize(minSize, RamUsageEstimator.NUM_BYTES_OBJECT_REF)][];
447 System.arraycopy(array, 0, newArray, 0, array.length);
454 public static float[][] grow(float[][] array) {
455 return grow(array, 1 + array.length);
458 public static float[][] shrink(float[][] array, int targetSize) {
459 assert targetSize >= 0: "size must be positive (got " + targetSize + "): likely integer overflow?";
460 final int newSize = getShrinkSize(array.length, targetSize, RamUsageEstimator.NUM_BYTES_OBJECT_REF);
461 if (newSize != array.length) {
462 float[][] newArray = new float[newSize][];
463 System.arraycopy(array, 0, newArray, 0, newSize);
471 * Returns hash of chars in range start (inclusive) to
474 public static int hashCode(char[] array, int start, int end) {
476 for (int i = end - 1; i >= start; i--)
477 code = code * 31 + array[i];
482 * Returns hash of bytes in range start (inclusive) to
485 public static int hashCode(byte[] array, int start, int end) {
487 for (int i = end - 1; i >= start; i--)
488 code = code * 31 + array[i];
493 // Since Arrays.equals doesn't implement offsets for equals
495 * See if two array slices are the same.
497 * @param left The left array to compare
498 * @param offsetLeft The offset into the array. Must be positive
499 * @param right The right array to compare
500 * @param offsetRight the offset into the right array. Must be positive
501 * @param length The length of the section of the array to compare
502 * @return true if the two arrays, starting at their respective offsets, are equal
504 * @see java.util.Arrays#equals(char[], char[])
506 public static boolean equals(char[] left, int offsetLeft, char[] right, int offsetRight, int length) {
507 if ((offsetLeft + length <= left.length) && (offsetRight + length <= right.length)) {
508 for (int i = 0; i < length; i++) {
509 if (left[offsetLeft + i] != right[offsetRight + i]) {
519 // Since Arrays.equals doesn't implement offsets for equals
521 * See if two array slices are the same.
523 * @param left The left array to compare
524 * @param offsetLeft The offset into the array. Must be positive
525 * @param right The right array to compare
526 * @param offsetRight the offset into the right array. Must be positive
527 * @param length The length of the section of the array to compare
528 * @return true if the two arrays, starting at their respective offsets, are equal
530 * @see java.util.Arrays#equals(char[], char[])
532 public static boolean equals(int[] left, int offsetLeft, int[] right, int offsetRight, int length) {
533 if ((offsetLeft + length <= left.length) && (offsetRight + length <= right.length)) {
534 for (int i = 0; i < length; i++) {
535 if (left[offsetLeft + i] != right[offsetRight + i]) {
545 public static int[] toIntArray(Collection<Integer> ints) {
547 final int[] result = new int[ints.size()];
554 assert upto == result.length;
559 /** SorterTemplate with custom {@link Comparator} */
560 private static <T> SorterTemplate getSorter(final T[] a, final Comparator<? super T> comp) {
561 return new SorterTemplate() {
563 protected void swap(int i, int j) {
570 protected int compare(int i, int j) {
571 return comp.compare(a[i], a[j]);
575 protected void setPivot(int i) {
580 protected int comparePivot(int j) {
581 return comp.compare(pivot, a[j]);
588 /** Natural SorterTemplate */
589 private static <T extends Comparable<? super T>> SorterTemplate getSorter(final T[] a) {
590 return new SorterTemplate() {
592 protected void swap(int i, int j) {
599 protected int compare(int i, int j) {
600 return a[i].compareTo(a[j]);
604 protected void setPivot(int i) {
609 protected int comparePivot(int j) {
610 return pivot.compareTo(a[j]);
617 // quickSorts (endindex is exclusive!):
620 * Sorts the given array slice using the {@link Comparator}. This method uses the quick sort
621 * algorithm, but falls back to insertion sort for small arrays.
622 * @param fromIndex start index (inclusive)
623 * @param toIndex end index (exclusive)
625 public static <T> void quickSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> comp) {
626 if (toIndex-fromIndex <= 1) return;
627 getSorter(a, comp).quickSort(fromIndex, toIndex-1);
631 * Sorts the given array using the {@link Comparator}. This method uses the quick sort
632 * algorithm, but falls back to insertion sort for small arrays.
634 public static <T> void quickSort(T[] a, Comparator<? super T> comp) {
635 quickSort(a, 0, a.length, comp);
639 * Sorts the given array slice in natural order. This method uses the quick sort
640 * algorithm, but falls back to insertion sort for small arrays.
641 * @param fromIndex start index (inclusive)
642 * @param toIndex end index (exclusive)
644 public static <T extends Comparable<? super T>> void quickSort(T[] a, int fromIndex, int toIndex) {
645 if (toIndex-fromIndex <= 1) return;
646 getSorter(a).quickSort(fromIndex, toIndex-1);
650 * Sorts the given array in natural order. This method uses the quick sort
651 * algorithm, but falls back to insertion sort for small arrays.
653 public static <T extends Comparable<? super T>> void quickSort(T[] a) {
654 quickSort(a, 0, a.length);
660 * Sorts the given array slice using the {@link Comparator}. This method uses the merge sort
661 * algorithm, but falls back to insertion sort for small arrays.
662 * @param fromIndex start index (inclusive)
663 * @param toIndex end index (exclusive)
665 public static <T> void mergeSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> comp) {
666 if (toIndex-fromIndex <= 1) return;
667 //System.out.println("SORT: " + (toIndex-fromIndex));
668 getSorter(a, comp).mergeSort(fromIndex, toIndex-1);
672 * Sorts the given array using the {@link Comparator}. This method uses the merge sort
673 * algorithm, but falls back to insertion sort for small arrays.
675 public static <T> void mergeSort(T[] a, Comparator<? super T> comp) {
676 mergeSort(a, 0, a.length, comp);
680 * Sorts the given array slice in natural order. This method uses the merge sort
681 * algorithm, but falls back to insertion sort for small arrays.
682 * @param fromIndex start index (inclusive)
683 * @param toIndex end index (exclusive)
685 public static <T extends Comparable<? super T>> void mergeSort(T[] a, int fromIndex, int toIndex) {
686 if (toIndex-fromIndex <= 1) return;
687 getSorter(a).mergeSort(fromIndex, toIndex-1);
691 * Sorts the given array in natural order. This method uses the merge sort
692 * algorithm, but falls back to insertion sort for small arrays.
694 public static <T extends Comparable<? super T>> void mergeSort(T[] a) {
695 mergeSort(a, 0, a.length);
701 * Sorts the given array slice using the {@link Comparator}. This method uses the insertion sort
702 * algorithm. It is only recommended to use this algorithm for partially sorted small arrays!
703 * @param fromIndex start index (inclusive)
704 * @param toIndex end index (exclusive)
706 public static <T> void insertionSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> comp) {
707 if (toIndex-fromIndex <= 1) return;
708 getSorter(a, comp).insertionSort(fromIndex, toIndex-1);
712 * Sorts the given array using the {@link Comparator}. This method uses the insertion sort
713 * algorithm. It is only recommended to use this algorithm for partially sorted small arrays!
715 public static <T> void insertionSort(T[] a, Comparator<? super T> comp) {
716 insertionSort(a, 0, a.length, comp);
720 * Sorts the given array slice in natural order. This method uses the insertion sort
721 * algorithm. It is only recommended to use this algorithm for partially sorted small arrays!
722 * @param fromIndex start index (inclusive)
723 * @param toIndex end index (exclusive)
725 public static <T extends Comparable<? super T>> void insertionSort(T[] a, int fromIndex, int toIndex) {
726 if (toIndex-fromIndex <= 1) return;
727 getSorter(a).insertionSort(fromIndex, toIndex-1);
731 * Sorts the given array in natural order. This method uses the insertion sort
732 * algorithm. It is only recommended to use this algorithm for partially sorted small arrays!
734 public static <T extends Comparable<? super T>> void insertionSort(T[] a) {
735 insertionSort(a, 0, a.length);