org.netbeans.modules.versioning.util.CollectionUtils Maven / Gradle / Ivy
/*
* 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.netbeans.modules.versioning.util;
import java.lang.reflect.Array;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Collection if utility method for working with {@code Collection}s and arrays.
*
* @author Marian Petras
* @since 1.9.1
*/
public final class CollectionUtils {
private CollectionUtils() {}
/**
* Finds index of the first occurence of an item in the given array.
* The items are compared using operator {@code ==}, method {@code equals()}
* is not used. It is legal to search for {@code null}.
*
* @param itemToFind object to search for
* @param array array of objects to be searched
* @return index of the first occurence of the given item in the array,
* or {@code -1} if not found
* @exception java.lang.IllegalArgumentException
* if the given array is {@code null}
* @since 1.9.1
*/
public static int findInArray(T[] array, U itemToFind) {
if (array == null) {
throw new IllegalArgumentException("null array"); //NOI18N
}
for (int i = 0; i < array.length; i++) {
if (array[i] == itemToFind) {
return i;
}
}
return -1;
}
/**
* Appends an item to an array.
*
* @param array array to append an item to
* @param itemToAppend item to be appended (may be {@code null})
* @return new array containing the same items, in the same order
* as the passed array, just one item longer, the given item
* being the last item
* @exception java.lang.NullPointerException
* if the passed array was {@code null}
* @since 1.9.1
*/
public static T[] appendItem(T[] array, T itemToAppend) {
if (array == null) {
throw new IllegalArgumentException("null array"); //NOI18N
}
T[] result = makeArray(array, array.length + 1);
if (array.length != 0) {
System.arraycopy(array, 0, result, 0, array.length);
}
result[array.length] = itemToAppend;
return result;
}
/**
* Removes a first occurence of the given item from an array, if present.
* The items are compared using operator {@code ==}, method {@code equals()}
* is not used. It is legal to ask for removal of item {@code null}.
*
* @param array array to remove an item from
* @param index item to be removed
* @return the passed array if the given item has not been found in the
* array, or a new array containing the same items as in the passed
* array, in the same order, just with the given item missing
*/
public static T[] removeItem(T[] array, U itemToRemove) {
if (array == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
int index = findInArray(array, itemToRemove);
return (index == -1) ? array : removeItem(array, index);
}
/**
* Removes a given item from an array.
* @param array array to remove an item from
* @param index index to the item to be removed
* @return new array containing the same items as in the passed array,
* in the same order, just with the given item missing
*/
public static T[] removeItem(T[] array, int index) {
if (array == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
if (index < 0) {
throw new IllegalArgumentException(
"negative index: " + index); //NOI18N
}
if (index >= array.length) {
throw new IllegalArgumentException(
"index out of bounds (array length: " + array.length//NOI18N
+ ", index: " + index + ')'); //NOI18N
}
T[] result = makeArray(array, array.length - 1);
if (index != 0) {
System.arraycopy(array, 0, result, 0, index);
}
if (index != array.length - 1) {
System.arraycopy(array, index + 1, result, index,
array.length - index - 1);
}
return result;
}
/**
* Returns array containing set of unique elements from the given array.
* I.e. the returned array will not contain any pair of non-null
* items a, b such that {@code a.equals(b)}.
* If the passed array contains one ore more {@code null} elements,
* the returned array will contain a single {@code null} element.
*
* The returned array may be the same instance as the passed array
* if the passed array did not contain any duplicate items.
*
* This method is only suitable for small arrays because it takes time
* O(n^2) where n is the number of elements in the array.
*
* @param array array to remove trailing duplicates elements from
* @return array being a copy of the passed array with duplicate items
* missing
* @exception java.lang.NullPointerException
* if the passed array was {@code null}
* @since 1.9.1
*/
public static T[] removeDuplicates(T[] array) {
if (array == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
if (array.length < 2) {
return array;
}
boolean nullItemFound = false;
int mainTopBound = array.length - 1;
int i;
for (i = 0; i < mainTopBound; i++) {
T item = array[i];
boolean isDuplicate = false;
if (item == null) {
nullItemFound = true;
for (int j = i + 1; j < array.length; j++) {
if (array[j] == null) {
isDuplicate = true;
break;
}
}
} else {
for (int j = i + 1; j < array.length; j++) {
if (equal(item, array[j])) {
isDuplicate = true;
array[j] = null; //clear item known to be a duplicate
}
}
}
if (isDuplicate) {
break;
}
}
if (i == mainTopBound) {
return array; //there were no duplicates in the array
}
T[] proResult = (T[]) Array.newInstance(
array.getClass().getComponentType(),
array.length - 1);
int count = i; //number of unique items known so far
if (count != 0) {
System.arraycopy(array, 0, proResult, 0, count);
}
for (i = i + 1; i < mainTopBound; i++) {
T item = array[i];
if (item == null) {
if (!nullItemFound) {
nullItemFound = true;
proResult[count++] = null; //store the first null-item
}
/*
* Skip all null-items. Each null-item is either the first
* null-item in the array and has been already stored to the
* result, or it is a cleared duplicate item and we do not want
* to compare it with other items.
*/
continue;
}
boolean isDuplicate = false;
for (int j = i + 1; j < array.length; j++) {
if (equal(item, array[j])) {
isDuplicate = true;
array[j] = null; //clear item known to be a duplicate
}
}
if (isDuplicate) {
continue;
}
proResult[count++] = array[i];
}
proResult[count++] = array[mainTopBound];
return shortenArray(proResult, count);
}
/**
* Returns array containing all non-{@code null} elements from the given
* array, in the same order.
*
* The returned array can be the same instance as the passed array
* if the passed array did not contain any {@code null} items.
*
* @param array array to remove {@code null} elements from
* @return the passed array, if it did not contain any {@code null} items,
* or a new array being a copy of the passed array with
* {@code null} items missing
* @exception java.lang.NullPointerException
* if the passed array was {@code null}
* @since 1.9.1
*/
public static T[] removeNulls(T[] array) {
if (array == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
int i = 0;
for (i = 0; i < array.length; i++) {
if (array[i] == null) {
break;
}
}
/* 'i' now contains number of non-null items */
if (i == array.length) { //there were no null-items
return array;
}
T[] proResult = (T[]) Array.newInstance(
array.getClass().getComponentType(),
array.length - 1);
int count = i; //number of non-null items
if (count != 0) {
System.arraycopy(array, 0, proResult, 0, count);
}
for (i = i + 1; i < array.length; i++) {
if (array[i] != null) {
proResult[count++] = array[i];
}
}
return shortenArray(proResult, count);
}
/**
* Returns array containing the same elements and in the same order
* as the array passed as an argument, except that all trailing {@code null}
* elements (if any) are missing.
*
* @param array array to remove trailing {@code null} elements from
* @return the passed array, if it did not contain any trailing
* {@code null} elements, or a new array being a copy of the
* passed array with trailing {@code null} elements missing
* @since 1.9.1
*/
public static T[] stripTrailingNulls(T[] array) {
if (array == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
/* count trailing nulls -> compute size of the resulting array */
int resultSize = array.length;
while ((resultSize > 0) && (array[resultSize - 1] == null)) {
resultSize--;
}
return shortenArray(array, resultSize);
}
/**
* Shortens the given array to the requested length by stripping last
* few items.
*
* @param array array to be shortened
* @param requestedLength requested length of the array
* @return the passed array if it was already of the requested length,
* or a new array containing the given number of items
* from the passed array, in the same order
* @exception java.lang.NullPointerException
* if the passed array was {@code null} or if the requested
* length was out of range (less than 0 or greater than
* the length of the passed array)
* @since 1.9.1
*/
public static T[] shortenArray(T[] array, int requestedLength) {
if (array == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
if (requestedLength < 0) {
throw new IllegalArgumentException(
"negative requested length (" + requestedLength + ')'); //NOI18N
}
if (requestedLength > array.length) {
throw new IllegalArgumentException(
"requested length (" + requestedLength //NOI18N
+ ") is greater than the current length (" //NOI18N
+ array.length + ')');
}
if (requestedLength == array.length) {
return array;
}
T[] result = makeArray(array, requestedLength);
if (requestedLength != 0) {
System.arraycopy(array, 0, result, 0, requestedLength);
}
return result;
}
/**
* Creates a copy of the given array.
*
* @param source array to be copied
* @return new array containing the same items and in the same order
* as the source array
* @exception java.lang.IllegalArgumentException
* if the source array is {@code null}
* @since 1.9.1
*/
public static T[] copyArray(T[] source) {
if (source == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
T[] result = makeArray(source, source.length);
System.arraycopy(source, 0, result, 0, source.length);
return result;
}
/**
* Makes a new array of the same type as the array passed as an argument.
*
* @param typeTemplate array to get the type of elements from
* @param length requested length of the new array
* @return new array of the type of the given array
* @exception java.lang.IllegalArgumentException
* if the passed array is {@code null}
* or if the requested length is negative
* @since 1.9.1
*/
public static T[] makeArray(T[] typeTemplate, int length) {
if (typeTemplate == null) {
throw new IllegalArgumentException("null"); //NOI18N
}
if (length < 0) {
throw new IllegalArgumentException("negative length"); //NOI18N
}
return (T[]) java.lang.reflect.Array.newInstance(
typeTemplate.getClass().getComponentType(),
length);
}
/**
* Compares whether the two arrays contain the same elements (in any order).
* {@code null} arrays are legal and are treated like empty arrays.
* Elements of the array are compared using identity check, method
* {@code equals()} is not used.
* Order of elements in the arrays is not taken into account.
* {@code null} elements in arrays are legal.
*
* @param a first array to be compared with the other array
* @param b second array to be compared with the other array
* @return {@code true} if the two arrays contain exactly the same object
* references as the other array, ignoring order of the elements
*/
public static boolean containSameObjects(Object[] a, Object[] b) {
int lengthA = (a != null) ? a.length : 0;
int lengthB = (b != null) ? b.length : 0;
if (lengthA != lengthB) {
return false;
}
final int length = lengthA;
if (length == 0) {
return true;
}
if (length == 1) {
return a[0] == b[0];
}
if (length == 2) {
return (a[0] == b[0]) && (a[1] == b[1])
|| (a[0] == b[1]) && (a[1] == b[0]);
}
return compareArrays(a, b, length,
new IdentityHashMap