package xapi.util;
import xapi.fu.In2Out1;
import xapi.fu.X_Fu;
import static xapi.fu.X_Fu.blank;
import static xapi.util.X_Runtime.isJavaScript;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutionException;
/**
* Generic purpose utility methods;
* this class has no fields, no
*
* @author "James X. Nelson (james@wetheinter.net)"
*
*/
public final class X_Util{
private X_Util() {}
public static boolean equal(final Object one, final Object two){
return one == two || (one != null && one.equals(two));
}
public static <T> T firstNotNull(final T first, final T second) {
return first == null ? second : first;
}
public static <T> T firstNotNull(final T first, final T second, final T third) {
return first == null ? second == null ? third : second : first;
}
@SuppressWarnings("unchecked")
public static <T> T firstNotNull(final T first, final T ... rest) {
if (first == null) {
for (final T t : rest) {
if (t != null) {
return t;
}
}
}
return first;
}
public static RuntimeException rethrow(Throwable e) {
if (e instanceof RuntimeException)
{
throw (RuntimeException)e;// Don't re-wrap
}
if (e instanceof Error)
{
throw ((Error)e);// Just rethrow errors without wrappers
}
while (// unwrap checked wrappers, for ease later on
e instanceof InvocationTargetException
|| e instanceof ExecutionException
) {
if (e.getCause()!=null){
e = e.getCause();
} else if (e == e.getCause()) {
break;
}
}
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
// throw unchecked.
throw new RuntimeException(e);
}
public static int zeroSafeInt(final Integer i) {
return i == null ? 0 : i;
}
public static double zeroSafeDouble(final Number i) {
return i == null ? 0 : i.doubleValue();
}
public static Throwable unwrap(Throwable e) {
if (X_Runtime.isDebug()) {
e.printStackTrace();// Avoid losing information in debug mode.
}
//don't use instanceof because we don't want to treat subclasses of RuntimeException as wrappers...
while (e.getClass().equals(RuntimeException.class) || e.getClass().equals(ExecutionException.class)) {
if (e.getCause() == null) {
return e;
}
e = e.getCause();
}
return e;
}
public static <T> T[] pushIfMissing(T[] array, T item) {
return pushIf(array, item, (b, i)->indexOf(array, item) == -1);
}
public static <T> T[] pushAllMissing(T[] array, T ... items) {
if (items == null || items.length == 0) {
return array;
}
T[] missing = blank(items);
int cnt = 0;
for (int i = 0; i < items.length; i++ ) {
final T item = items[i];
int index = indexOf(array, items[i]);
// record missing items
if (index == -1) {
// do not double-add items.
if (indexOf(missing, item) == -1) {
missing[cnt++] = item;
}
}
}
if (cnt == 0) {
return array;
}
final T[] result = X_Fu.copy(array, array.length + cnt);
System.arraycopy(missing, 0, result, array.length, cnt);
return result;
}
public static <T> T[] pushIf(T[] beforeFinished, T t, In2Out1<T[], T, Boolean> filter) {
if (filter.io(beforeFinished, t)) {
return pushOnto(beforeFinished, t);
}
return beforeFinished;
}
public static <T> T[] pushOnto(T[] beforeFinished, T t) {
if (isJavaScript()) {
beforeFinished[beforeFinished.length] = t;
return beforeFinished;
} else {
T[] copy = X_Fu.push(beforeFinished, t);
return copy;
}
}
public static boolean isArray(Object items) {
if (items == null) {
return false;
}
if (isJavaScript()) {
return jsniIsArray(items);
} else {
return items.getClass().isArray();
}
}
private static native boolean jsniIsArray(Object items)
/*-{
return Array.isArray(items);
}-*/;
public static <K> int indexOf(K[] from, K match) {
if (from == null || from.length == 0) {
return -1;
}
if (match == null) {
for (int i = 0; i < from.length; i++) {
if (from[i] == null) {
return i;
}
}
} else {
for (int i = 0; i < from.length; i++) {
if (match.equals(from[i])) {
return i;
}
}
}
return -1;
}
public static void maybeRethrow(Exception e) {
if (unwrap(e) instanceof InterruptedException) {
rethrow(e);
}
}
}