193 lines
5.2 KiB
Java
193 lines
5.2 KiB
Java
package dorkbox.util.messagebus.utils;
|
|
|
|
import dorkbox.util.messagebus.common.adapter.JavaVersionAdapter;
|
|
|
|
import java.lang.reflect.Array;
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.Map;
|
|
|
|
public final
|
|
class ClassUtils {
|
|
|
|
private final Map<Class<?>, Class<?>> arrayCache;
|
|
private final Map<Class<?>, Class<?>[]> superClassesCache;
|
|
|
|
public
|
|
ClassUtils(final float loadFactor) {
|
|
this.arrayCache = JavaVersionAdapter.concurrentMap(32, loadFactor, 1);
|
|
this.superClassesCache = JavaVersionAdapter.concurrentMap(32, loadFactor, 1);
|
|
}
|
|
|
|
/**
|
|
* never returns null
|
|
* never reset, since it never needs to be reset (as the class hierarchy doesn't change at runtime)
|
|
* <p/>
|
|
* if parameter clazz is of type array, then the super classes are of array type as well
|
|
* <p/>
|
|
* protected by read lock by caller. The cache version is called first, by write lock
|
|
*/
|
|
public
|
|
Class<?>[] getSuperClasses(final Class<?> clazz) {
|
|
// this is never reset, since it never needs to be.
|
|
final Map<Class<?>, Class<?>[]> local = this.superClassesCache;
|
|
|
|
Class<?>[] classes = local.get(clazz);
|
|
|
|
if (classes == null) {
|
|
// publish all super types of class
|
|
final Class<?>[] superTypes = ReflectionUtils.getSuperTypes(clazz);
|
|
final int length = superTypes.length;
|
|
|
|
final ArrayList<Class<?>> newList = new ArrayList<Class<?>>(length);
|
|
|
|
Class<?> c;
|
|
final boolean isArray = clazz.isArray();
|
|
|
|
if (isArray) {
|
|
for (int i = 0; i < length; i++) {
|
|
c = superTypes[i];
|
|
|
|
c = getArrayClass(c);
|
|
|
|
if (c != clazz) {
|
|
newList.add(c);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
for (int i = 0; i < length; i++) {
|
|
c = superTypes[i];
|
|
|
|
if (c != clazz) {
|
|
newList.add(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
classes = new Class<?>[newList.size()];
|
|
newList.toArray(classes);
|
|
local.put(clazz, classes);
|
|
}
|
|
|
|
return classes;
|
|
}
|
|
|
|
/**
|
|
* race conditions will result in duplicate answers, which we don't care if happens
|
|
* never returns null
|
|
* never reset
|
|
*/
|
|
public
|
|
Class<?> getArrayClass(final Class<?> c) {
|
|
final Map<Class<?>, Class<?>> arrayCache = this.arrayCache;
|
|
Class<?> clazz = arrayCache.get(c);
|
|
|
|
if (clazz == null) {
|
|
// messy, but the ONLY way to do it. Array super types are also arrays
|
|
final Object[] newInstance = (Object[]) Array.newInstance(c, 1);
|
|
clazz = newInstance.getClass();
|
|
arrayCache.put(c, clazz);
|
|
}
|
|
|
|
return clazz;
|
|
}
|
|
|
|
|
|
/**
|
|
* Clears the caches
|
|
*/
|
|
public
|
|
void clear() {
|
|
this.arrayCache.clear();
|
|
this.superClassesCache.clear();
|
|
}
|
|
|
|
public static
|
|
<T> ArrayList<T> findCommon(final T[] arrayOne, final T[] arrayTwo) {
|
|
|
|
T[] arrayToHash;
|
|
T[] arrayToSearch;
|
|
|
|
final int size1 = arrayOne.length;
|
|
final int size2 = arrayTwo.length;
|
|
|
|
final int hashSize;
|
|
final int searchSize;
|
|
|
|
if (size1 < size2) {
|
|
hashSize = size1;
|
|
searchSize = size2;
|
|
arrayToHash = arrayOne;
|
|
arrayToSearch = arrayTwo;
|
|
}
|
|
else {
|
|
hashSize = size2;
|
|
searchSize = size1;
|
|
arrayToHash = arrayTwo;
|
|
arrayToSearch = arrayOne;
|
|
}
|
|
|
|
|
|
final ArrayList<T> intersection = new ArrayList<T>(searchSize);
|
|
|
|
final HashSet<T> hashedArray = new HashSet<T>();
|
|
for (int i = 0; i < hashSize; i++) {
|
|
T t = arrayToHash[i];
|
|
hashedArray.add(t);
|
|
}
|
|
|
|
for (int i = 0; i < searchSize; i++) {
|
|
T t = arrayToSearch[i];
|
|
if (hashedArray.contains(t)) {
|
|
intersection.add(t);
|
|
}
|
|
}
|
|
|
|
return intersection;
|
|
}
|
|
|
|
public static
|
|
<T> ArrayList<T> findCommon(final ArrayList<T> arrayOne, final ArrayList<T> arrayTwo) {
|
|
|
|
ArrayList<T> arrayToHash;
|
|
ArrayList<T> arrayToSearch;
|
|
|
|
final int size1 = arrayOne.size();
|
|
final int size2 = arrayTwo.size();
|
|
|
|
final int hashSize;
|
|
final int searchSize;
|
|
|
|
if (size1 < size2) {
|
|
hashSize = size1;
|
|
searchSize = size2;
|
|
arrayToHash = arrayOne;
|
|
arrayToSearch = arrayTwo;
|
|
}
|
|
else {
|
|
hashSize = size2;
|
|
searchSize = size1;
|
|
arrayToHash = arrayTwo;
|
|
arrayToSearch = arrayOne;
|
|
}
|
|
|
|
ArrayList<T> intersection = new ArrayList<T>(searchSize);
|
|
|
|
HashSet<T> hashedArray = new HashSet<T>();
|
|
for (int i = 0; i < hashSize; i++) {
|
|
T t = arrayToHash.get(i);
|
|
hashedArray.add(t);
|
|
}
|
|
|
|
for (int i = 0; i < searchSize; i++) {
|
|
T t = arrayToSearch.get(i);
|
|
if (hashedArray.contains(t)) {
|
|
intersection.add(t);
|
|
}
|
|
}
|
|
|
|
return intersection;
|
|
}
|
|
}
|