com.twelvemonkeys.util.CollectionUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.fop Show documentation
Show all versions of org.apache.fop Show documentation
The core maven build properties
The newest version!
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.util;
import com.twelvemonkeys.lang.Validate;
import java.lang.reflect.Array;
import java.util.*;
import static com.twelvemonkeys.lang.Validate.isTrue;
import static com.twelvemonkeys.lang.Validate.notNull;
/**
* A utility class with some useful collection-related functions.
*
* @author Harald Kuhr
* @author Eirik Torske
* @author last modified by $Author: haku $
* @version $Id: com/twelvemonkeys/util/CollectionUtil.java#3 $
* @see Collections
* @see Arrays
*/
public final class CollectionUtil {
/**
* Testing only.
*
* @param pArgs command line arguents
*/
@SuppressWarnings({"UnusedDeclaration", "UnusedAssignment", "unchecked"})
public static void main(String[] pArgs) {
int howMany = 1000;
if (pArgs.length > 0) {
howMany = Integer.parseInt(pArgs[0]);
}
long start;
long end;
/*
int[] intArr1 = new int[] {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};
int[] intArr2 = new int[] {
10, 11, 12, 13, 14, 15, 16, 17, 18, 19
};
start = System.currentTimeMillis();
for (int i = 0; i < howMany; i++) {
intArr1 = (int[]) mergeArrays(intArr1, 0, intArr1.length, intArr2, 0, intArr2.length);
}
end = System.currentTimeMillis();
System.out.println("mergeArrays: " + howMany + " * " + intArr2.length + " ints took " + (end - start) + " milliseconds (" + intArr1.length
+ ")");
*/
////////////////////////////////
String[] stringArr1 = new String[]{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"
};
/*
String[] stringArr2 = new String[] {
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
start = System.currentTimeMillis();
for (int i = 0; i < howMany; i++) {
stringArr1 = (String[]) mergeArrays(stringArr1, 0, stringArr1.length, stringArr2, 0, stringArr2.length);
}
end = System.currentTimeMillis();
System.out.println("mergeArrays: " + howMany + " * " + stringArr2.length + " Strings took " + (end - start) + " milliseconds ("
+ stringArr1.length + ")");
start = System.currentTimeMillis();
while (intArr1.length > stringArr2.length) {
intArr1 = (int[]) subArray(intArr1, 0, intArr1.length - stringArr2.length);
}
end = System.currentTimeMillis();
System.out.println("subArray: " + howMany + " * " + intArr2.length + " ints took " + (end - start) + " milliseconds (" + intArr1.length
+ ")");
start = System.currentTimeMillis();
while (stringArr1.length > stringArr2.length) {
stringArr1 = (String[]) subArray(stringArr1, stringArr2.length);
}
end = System.currentTimeMillis();
System.out.println("subArray: " + howMany + " * " + stringArr2.length + " Strings took " + (end - start) + " milliseconds ("
+ stringArr1.length + ")");
*/
stringArr1 = new String[]{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
System.out.println("\nFilterIterators:\n");
List list = Arrays.asList(stringArr1);
Iterator iter = new FilterIterator(list.iterator(), new FilterIterator.Filter() {
public boolean accept(Object pElement) {
return ((String) pElement).length() > 5;
}
});
while (iter.hasNext()) {
String str = (String) iter.next();
System.out.println(str + " has more than 5 letters!");
}
iter = new FilterIterator(list.iterator(), new FilterIterator.Filter() {
public boolean accept(Object pElement) {
return ((String) pElement).length() <= 5;
}
});
while (iter.hasNext()) {
String str = (String) iter.next();
System.out.println(str + " has less than, or exactly 5 letters!");
}
start = System.currentTimeMillis();
for (int i = 0; i < howMany; i++) {
iter = new FilterIterator(list.iterator(), new FilterIterator.Filter() {
public boolean accept(Object pElement) {
return ((String) pElement).length() <= 5;
}
});
while (iter.hasNext()) {
iter.next();
System.out.print("");
}
}
// end = System.currentTimeMillis();
// System.out.println("Time: " + (end - start) + " ms");
// System.out.println("\nClosureCollection:\n");
// forEach(list, new Closure() {
//
// public void execute(Object pElement) {
//
// String str = (String) pElement;
//
// if (str.length() > 5) {
// System.out.println(str + " has more than 5 letters!");
// }
// else {
// System.out.println(str + " has less than, or exactly 5 letters!");
// }
// }
// });
// start = System.currentTimeMillis();
// for (int i = 0; i < howMany; i++) {
// forEach(list, new Closure() {
//
// public void execute(Object pElement) {
//
// String str = (String) pElement;
//
// if (str.length() <= 5) {
// System.out.print("");
// }
// }
// });
// }
// end = System.currentTimeMillis();
// System.out.println("Time: " + (end - start) + " ms");
}
// Disallow creating objects of this type
private CollectionUtil() {}
/**
* Merges two arrays into a new array. Elements from array1 and array2 will
* be copied into a new array, that has array1.length + array2.length
* elements.
*
* @param pArray1 First array
* @param pArray2 Second array, must be compatible with (assignable from)
* the first array
* @return A new array, containing the values of array1 and array2. The
* array (wrapped as an object), will have the length of array1 +
* array2, and can be safely cast to the type of the array1
* parameter.
* @see #mergeArrays(Object,int,int,Object,int,int)
* @see java.lang.System#arraycopy(Object,int,Object,int,int)
*/
public static Object mergeArrays(Object pArray1, Object pArray2) {
return mergeArrays(pArray1, 0, Array.getLength(pArray1), pArray2, 0, Array.getLength(pArray2));
}
/**
* Merges two arrays into a new array. Elements from pArray1 and pArray2 will
* be copied into a new array, that has pLength1 + pLength2 elements.
*
* @param pArray1 First array
* @param pOffset1 the offset into the first array
* @param pLength1 the number of elements to copy from the first array
* @param pArray2 Second array, must be compatible with (assignable from)
* the first array
* @param pOffset2 the offset into the second array
* @param pLength2 the number of elements to copy from the second array
* @return A new array, containing the values of pArray1 and pArray2. The
* array (wrapped as an object), will have the length of pArray1 +
* pArray2, and can be safely cast to the type of the pArray1
* parameter.
* @see java.lang.System#arraycopy(Object,int,Object,int,int)
*/
@SuppressWarnings({"SuspiciousSystemArraycopy"})
public static Object mergeArrays(Object pArray1, int pOffset1, int pLength1, Object pArray2, int pOffset2, int pLength2) {
Class class1 = pArray1.getClass();
Class type = class1.getComponentType();
// Create new array of the new length
Object array = Array.newInstance(type, pLength1 + pLength2);
System.arraycopy(pArray1, pOffset1, array, 0, pLength1);
System.arraycopy(pArray2, pOffset2, array, pLength1, pLength2);
return array;
}
/**
* Creates an array containing a subset of the original array.
* If the sub array is same length as the original
* ({@code pStart == 0}), the original array will be returned.
*
* @param pArray the original array
* @param pStart the start index of the original array
* @return a subset of the original array, or the original array itself,
* if {@code pStart} is 0.
*
* @throws IllegalArgumentException if {@code pArray} is {@code null} or
* if {@code pArray} is not an array.
* @throws ArrayIndexOutOfBoundsException if {@code pStart} < 0
*/
public static Object subArray(Object pArray, int pStart) {
return subArray(pArray, pStart, -1);
}
/**
* Creates an array containing a subset of the original array.
* If the sub array is same length as the original
* ({@code pStart == 0}), the original array will be returned.
*
* @param the type of array
* @param pArray the original array
* @param pStart the start index of the original array
* @return a subset of the original array, or the original array itself,
* if {@code pStart} is 0.
*
* @throws IllegalArgumentException if {@code pArray} is {@code null}
* @throws ArrayIndexOutOfBoundsException if {@code pStart} < 0
*/
public static T[] subArray(T[] pArray, int pStart) {
return subArray(pArray, pStart, -1);
}
/**
* Creates an array containing a subset of the original array.
* If the {@code pLength} parameter is negative, it will be ignored.
* If there are not {@code pLength} elements in the original array
* after {@code pStart}, the {@code pLength} parameter will be
* ignored.
* If the sub array is same length as the original, the original array will
* be returned.
*
* @param pArray the original array
* @param pStart the start index of the original array
* @param pLength the length of the new array
* @return a subset of the original array, or the original array itself,
* if {@code pStart} is 0 and {@code pLength} is either
* negative, or greater or equal to {@code pArray.length}.
*
* @throws IllegalArgumentException if {@code pArray} is {@code null} or
* if {@code pArray} is not an array.
* @throws ArrayIndexOutOfBoundsException if {@code pStart} < 0
*/
@SuppressWarnings({"SuspiciousSystemArraycopy"})
public static Object subArray(Object pArray, int pStart, int pLength) {
Validate.notNull(pArray, "array");
// Get component type
Class type;
// Sanity check start index
if (pStart < 0) {
throw new ArrayIndexOutOfBoundsException(pStart + " < 0");
}
// Check if argument is array
else if ((type = pArray.getClass().getComponentType()) == null) {
// NOTE: No need to test class.isArray(), really
throw new IllegalArgumentException("Not an array: " + pArray);
}
// Store original length
int originalLength = Array.getLength(pArray);
// Find new length, stay within bounds
int newLength = (pLength < 0)
? Math.max(0, originalLength - pStart)
: Math.min(pLength, Math.max(0, originalLength - pStart));
// Store result
Object result;
if (newLength < originalLength) {
// Create sub array & copy into
result = Array.newInstance(type, newLength);
System.arraycopy(pArray, pStart, result, 0, newLength);
}
else {
// Just return original array
// NOTE: This can ONLY happen if pStart == 0
result = pArray;
}
// Return
return result;
}
/**
* Creates an array containing a subset of the original array.
* If the {@code pLength} parameter is negative, it will be ignored.
* If there are not {@code pLength} elements in the original array
* after {@code pStart}, the {@code pLength} parameter will be
* ignored.
* If the sub array is same length as the original, the original array will
* be returned.
*
* @param the type of array
* @param pArray the original array
* @param pStart the start index of the original array
* @param pLength the length of the new array
* @return a subset of the original array, or the original array itself,
* if {@code pStart} is 0 and {@code pLength} is either
* negative, or greater or equal to {@code pArray.length}.
*
* @throws IllegalArgumentException if {@code pArray} is {@code null}
* @throws ArrayIndexOutOfBoundsException if {@code pStart} < 0
*/
@SuppressWarnings("unchecked")
public static T[] subArray(T[] pArray, int pStart, int pLength) {
return (T[]) subArray((Object) pArray, pStart, pLength);
}
public static Iterator iterator(final Enumeration pEnum) {
notNull(pEnum, "enumeration");
return new Iterator() {
public boolean hasNext() {
return pEnum.hasMoreElements();
}
public T next() {
return pEnum.nextElement();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Adds all elements of the iterator to the collection.
*
* @param pCollection the collection
* @param pIterator the elements to add
*
* @throws UnsupportedOperationException if {@code add} is not supported by
* the given collection.
* @throws ClassCastException class of the specified element prevents it
* from being added to this collection.
* @throws NullPointerException if the specified element is {@code null} and this
* collection does not support {@code null} elements.
* @throws IllegalArgumentException some aspect of this element prevents
* it from being added to this collection.
*/
public static void addAll(Collection pCollection, Iterator extends E> pIterator) {
while (pIterator.hasNext()) {
pCollection.add(pIterator.next());
}
}
// Is there a use case where Arrays.asList(pArray).iterator() can't ne used?
/**
* Creates a thin {@link Iterator} wrapper around an array.
*
* @param pArray the array to iterate
* @return a new {@link ListIterator}
* @throws IllegalArgumentException if {@code pArray} is {@code null},
* {@code pStart < 0}, or
* {@code pLength > pArray.length - pStart}
*/
public static ListIterator iterator(final E[] pArray) {
return iterator(pArray, 0, notNull(pArray).length);
}
/**
* Creates a thin {@link Iterator} wrapper around an array.
*
* @param pArray the array to iterate
* @param pStart the offset into the array
* @param pLength the number of elements to include in the iterator
* @return a new {@link ListIterator}
* @throws IllegalArgumentException if {@code pArray} is {@code null},
* {@code pStart < 0}, or
* {@code pLength > pArray.length - pStart}
*/
public static ListIterator iterator(final E[] pArray, final int pStart, final int pLength) {
return new ArrayIterator(pArray, pStart, pLength);
}
/**
* Creates an inverted mapping of the key/value pairs in the given map.
*
* @param pSource the source map
* @return a new {@code Map} of same type as {@code pSource}
* @throws IllegalArgumentException if {@code pSource == null},
* or if a new map can't be instantiated,
* or if source map contains duplicates.
*
* @see #invert(java.util.Map, java.util.Map, DuplicateHandler)
*/
public static Map invert(Map pSource) {
return invert(pSource, null, null);
}
/**
* Creates an inverted mapping of the key/value pairs in the given map.
* Optionally, a duplicate handler may be specified, to resolve duplicate keys in the result map.
*
* @param pSource the source map
* @param pResult the map used to contain the result, may be {@code null},
* in that case a new {@code Map} of same type as {@code pSource} is created.
* The result map should be empty, otherwise duplicate values will need to be resolved.
* @param pHandler duplicate handler, may be {@code null} if source map don't contain duplicate values
* @return {@code pResult}, or a new {@code Map} if {@code pResult == null}
* @throws IllegalArgumentException if {@code pSource == null},
* or if result map is {@code null} and a new map can't be instantiated,
* or if source map contains duplicate values and {@code pHandler == null}.
*/
// TODO: Create a better duplicate handler, that takes Entries as parameters and returns an Entry
public static Map invert(Map pSource, Map pResult, DuplicateHandler pHandler) {
if (pSource == null) {
throw new IllegalArgumentException("source == null");
}
Map result = pResult;
if (result == null) {
try {
//noinspection unchecked
result = pSource.getClass().newInstance();
}
catch (InstantiationException e) {
// Handled below
}
catch (IllegalAccessException e) {
// Handled below
}
if (result == null) {
throw new IllegalArgumentException("result == null and source class " + pSource.getClass() + " cannot be instantiated.");
}
}
// Copy entries into result map, inversed
Set> entries = pSource.entrySet();
for (Map.Entry entry : entries) {
V newKey = entry.getValue();
K newValue = entry.getKey();
// Handle dupliates
if (result.containsKey(newKey)) {
if (pHandler != null) {
newValue = pHandler.resolve(result.get(newKey), newValue);
}
else {
throw new IllegalArgumentException("Result would include duplicate keys, but no DuplicateHandler specified.");
}
}
result.put(newKey, newValue);
}
return result;
}
public static Comparator reverseOrder(final Comparator pOriginal) {
return new ReverseComparator(pOriginal);
}
private static class ReverseComparator implements Comparator {
private final Comparator comparator;
public ReverseComparator(final Comparator pComparator) {
comparator = notNull(pComparator);
}
public int compare(T pLeft, T pRight) {
int result = comparator.compare(pLeft, pRight);
// We can't simply return -result, as -Integer.MIN_VALUE == Integer.MIN_VALUE.
return -(result | (result >>> 1));
}
}
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
static , E> T generify(final Iterator> pIterator, final Class pElementType) {
return (T) pIterator;
}
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
static , E> T generify(final Collection> pCollection, final Class pElementType) {
return (T) pCollection;
}
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
static , K, V> T generify(final Map, ?> pMap, final Class pKeyType, final Class pValueType) {
return (T) pMap;
}
@SuppressWarnings({"unchecked"})
static , E> T generify2(Collection> pCollection) {
return (T) pCollection;
}
private static class ArrayIterator implements ListIterator {
private int next;
private final int start;
private final int length;
private final E[] array;
public ArrayIterator(final E[] pArray, final int pStart, final int pLength) {
array = notNull(pArray, "array");
start = isTrue(pStart >= 0, pStart, "start < 0: %d");
length = isTrue(pLength <= pArray.length - pStart, pLength, "length > array.length - start: %d");
next = start;
}
public boolean hasNext() {
return next < length + start;
}
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
try {
return array[next++];
}
catch (ArrayIndexOutOfBoundsException e) {
NoSuchElementException nse = new NoSuchElementException(e.getMessage());
nse.initCause(e);
throw nse;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
public void add(E pElement) {
throw new UnsupportedOperationException();
}
public boolean hasPrevious() {
return next > start;
}
public int nextIndex() {
return next - start;
}
public E previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
try {
return array[--next];
}
catch (ArrayIndexOutOfBoundsException e) {
NoSuchElementException nse = new NoSuchElementException(e.getMessage());
nse.initCause(e);
throw nse;
}
}
public int previousIndex() {
return nextIndex() - 1;
}
public void set(E pElement) {
array[next - 1] = pElement;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy