/* * Copyright 2013 Cameron Beccario * * 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 net.nullschool.util; import java.lang.reflect.Type; import java.util.*; /** * 2013-02-11<p/> * * Utility methods for operating on arrays. * * @author Cameron Beccario */ public class ArrayTools { private ArrayTools() { throw new AssertionError(); } /** * Immutable Object[] of length 0. */ public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; /** * Immutable Class[] of length 0. */ public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; /** * Immutable Type[] of length 0. */ public static final Type[] EMPTY_TYPE_ARRAY = new Type[0]; /** * Returns the index of the specified element's first occurrence in the provided array. If the element * cannot be found, -1 is returned. Element comparisons are made exactly as specified by {@link Objects#equals}. * * @param element the element to find * @param array the array to search * @param <T> the element type * @return the index of the first occurrence of the element, or -1 if it cannot be found. * @throws NullPointerException if the array is null */ public static <T> int indexOf(T element, T[] array) { if (element == null) { for (int i = 0; i < array.length; i++) { if (array[i] == null) { return i; } } } else { for (int i = 0; i < array.length; i++) { if (element.equals(array[i])) { return i; } } } return -1; } /** * Returns the index of the specified element's first occurrence in the provided array, searching from * {@code fromIndex} (inclusive) up to {@code toIndex} (exclusive). If the element cannot be found, -1 * is returned. Element comparisons are made exactly as specified by {@link Objects#equals}. * * @param element the element to find * @param array the array to search * @param fromIndex the index at which to start searching * @param toIndex the index at which to stop searching * @param <T> the element type * @return the index of the first occurrence of the element in the search range, or -1 if it cannot be found. * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws IndexOutOfBoundsException if {@code fromIndex < 0 || toIndex > array.length} * @throws NullPointerException if the array is null */ public static <T> int indexOf(T element, T[] array, int fromIndex, int toIndex) { checkRange(fromIndex, toIndex, array.length); if (element == null) { for (int i = fromIndex; i < toIndex; i++) { if (array[i] == null) { return i; } } } else { for (int i = fromIndex; i < toIndex; i++) { if (element.equals(array[i])) { return i; } } } return -1; } /** * Returns the index of the specified element's first occurrence in the provided array. If the element * cannot be found, -1 is returned. Element comparisons are made using either the given comparator exactly * as specified by {@link Comparator#compare}, or the element's {@link Comparable natural ordering} if the * comparator is null. Note the array is traversed linearly. If the array is sorted, {@link * java.util.Arrays#binarySearch(Object[], Object, Comparator)} will offer better performance. * * @param element the element to find * @param array the array to search * @param comparator the comparator to use for equality testing, or null if natural ordering should be used. * @param <T> the element type * @return the index of the first occurrence of the element, or -1 if it cannot be found. * @throws NullPointerException if the array is null or the comparison does not allow nulls. * @throws ClassCastException if the element is not comparable to the elements of the array. */ public static <T> int indexOf(T element, T[] array, Comparator<? super T> comparator) { if (comparator == null) { for (int i = 0; i < array.length; i++) { // Cast to Comparable<T> is safe because compareTo method will do type checking. @SuppressWarnings("unchecked") Comparable<T> comparable = (Comparable<T>)array[i]; if (comparable.compareTo(element) == 0) { return i; } } } else { for (int i = 0; i < array.length; i++) { if (comparator.compare(array[i], element) == 0) { return i; } } } return -1; } /** * Returns the index of the specified element's first occurrence in the provided array, searching from * {@code fromIndex} (inclusive) up to {@code toIndex} (exclusive). If the element * cannot be found, -1 is returned. Element comparisons are made using either the given comparator exactly * as specified by {@link Comparator#compare}, or the element's {@link Comparable natural ordering} if the * comparator is null. Note the array is traversed linearly. If the array is sorted, {@link * java.util.Arrays#binarySearch(Object[], int, int, Object, Comparator)} will offer better performance. * * @param element the element to find * @param array the array to search * @param fromIndex the index at which to start searching * @param toIndex the index at which to stop searching * @param comparator the comparator to use for equality testing, or null if natural ordering should be used. * @param <T> the element type * @return the index of the first occurrence of the element, or -1 if it cannot be found. * @throws IllegalArgumentException if {@code fromIndex > toIndex} * @throws IndexOutOfBoundsException if {@code fromIndex < 0 || toIndex > array.length} * @throws NullPointerException if the array is null or the comparison does not allow nulls. * @throws ClassCastException if the element is not comparable to the elements of the array. */ public static <T> int indexOf(T element, T[] array, int fromIndex, int toIndex, Comparator<? super T> comparator) { checkRange(fromIndex, toIndex, array.length); if (comparator == null) { for (int i = fromIndex; i < toIndex; i++) { // Cast to Comparable<T> is safe because compareTo method will do type checking. @SuppressWarnings("unchecked") Comparable<T> comparable = (Comparable<T>)array[i]; if (comparable.compareTo(element) == 0) { return i; } } } else { for (int i = fromIndex; i < toIndex; i++) { if (comparator.compare(array[i], element) == 0) { return i; } } } return -1; } /** * Returns the index of the specified element's last occurrence in the provided array. If the element * cannot be found, -1 is returned. Element comparisons are made exactly as specified by {@link Objects#equals}. * * @param element the element to find * @param array the array to search * @param <T> the element type * @return the index of the last occurrence of the element, or -1 if it cannot be found. * @throws NullPointerException if the array is null */ public static <T> int lastIndexOf(T element, T[] array) { if (element == null) { for (int i = array.length - 1; i >= 0; i--) { if (array[i] == null) { return i; } } } else { for (int i = array.length - 1; i >= 0; i--) { if (element.equals(array[i])) { return i; } } } return -1; } /** * Checks that a range fits within an array of the specified length. * * @param fromIndex the starting index of the range, inclusive. * @param toIndex the ending index of the range, exclusive. * @param length the length of the array. * @throws IndexOutOfBoundsException if fromIndex is less than zero or toIndex is greater than length. * @throws IllegalArgumentException if fromIndex is greater than toIndex. */ public static void checkRange(int fromIndex, int toIndex, int length) { if (fromIndex < 0 || toIndex > length) { throw new IndexOutOfBoundsException( String.format("range [%d, %d) is outside bounds [%d, %d)", fromIndex, toIndex, 0, length)); } if (fromIndex > toIndex) { throw new IllegalArgumentException( String.format("fromIndex %d cannot be greater than toIndex %d", fromIndex, toIndex)); } } /** * Sorts the specified array exactly as described by {@link Arrays#sort(Object[])}, returning the same array * instance. * * @param a the array to sort. * @throws ClassCastException if some elements of the array are not mutually comparable. * @throws IllegalArgumentException if the elements' natural ordering violates the {@link Comparable} contract. * @return the exact array instance passed to this method, sorted. */ public static <T> T[] sort(T[] a) { Arrays.sort(a); return a; } /** * Sorts the specified array exactly as described by {@link Arrays#sort(Object[], Comparator)}, returning * the same array instance. * * @param a the array to sort. * @param c the comparator to use for sorting, or null if natural ordering should be used. * @throws ClassCastException if some elements of the array are not mutually comparable. * @throws IllegalArgumentException if the comparator violates the {@link Comparator} contract. * @return the exact array instance passed to this method, sorted. */ public static <T> T[] sort(T[] a, Comparator<? super T> c) { Arrays.sort(a, c); return a; } }