
com.simplaex.bedrock.Control Maven / Gradle / Ivy
package com.simplaex.bedrock;
import lombok.*;
import lombok.experimental.UtilityClass;
import lombok.experimental.Wither;
import javax.annotation.Nonnull;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.UnaryOperator;
/**
* Missing control structures for Java.
*/
@UtilityClass
@SuppressWarnings("WeakerAccess")
public class Control {
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static class TypeOfBranch {
private final Class clazz;
private final ThrowingFunction callable;
}
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static class TypeOfVoidBranch {
private final Class clazz;
private final ThrowingConsumer callable;
}
@Nonnull
public static TypeOfBranch type(@Nonnull final Class clazz, @Nonnull final ThrowingFunction f) {
return new TypeOfBranch<>(clazz, f);
}
@Nonnull
public static TypeOfVoidBranch type_(@Nonnull final Class clazz, @Nonnull final ThrowingConsumer f) {
return new TypeOfVoidBranch<>(clazz, f);
}
@SuppressWarnings("unchecked")
@SafeVarargs
public static T typeOf(final Object value, final TypeOfBranch, ? extends T>... typeOfBranches) {
for (val branch : typeOfBranches) {
if (branch.getClazz().isAssignableFrom(value.getClass())) {
return Try.execute(() -> (T) ((ThrowingFunction) branch.getCallable()).execute(value)).orElseThrowRuntime();
}
}
return null;
}
@SuppressWarnings("unchecked")
public static void typeOf(final Object value, final TypeOfVoidBranch>... branches) {
for (val branch : branches) {
if (branch.getClazz().isAssignableFrom(value.getClass())) {
Try.run(() -> ((ThrowingConsumer) branch.getCallable()).accept(value));
return;
}
}
}
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static class ValueOfBranch {
private final A value;
private final ThrowingFunction callable;
}
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static class ValueOfVoidBranch {
private final A value;
private final ThrowingConsumer callable;
}
@Nonnull
public static ValueOfBranch value(@Nonnull final A value, @Nonnull final ThrowingFunction f) {
return new ValueOfBranch<>(value, f);
}
@Nonnull
public static ValueOfVoidBranch value_(@Nonnull final A value, @Nonnull final ThrowingConsumer f) {
return new ValueOfVoidBranch<>(value, f);
}
@SuppressWarnings("unchecked")
@SafeVarargs
public static T valueOf(final Object value, final ValueOfBranch, ? extends T>... typeOfBranches) {
for (val branch : typeOfBranches) {
if (Objects.equals(value, branch.getValue())) {
return Try.execute(() -> (T) ((ThrowingFunction) branch.getCallable()).execute(value)).orElseThrowRuntime();
}
}
return null;
}
@SuppressWarnings("unchecked")
public static void valueOf(final Object value, final ValueOfVoidBranch>... branches) {
for (val branch : branches) {
if (Objects.equals(value, branch.getValue())) {
Try.run(() -> ((ThrowingConsumer) branch.getCallable()).accept(value));
return;
}
}
}
public static Thread.UncaughtExceptionHandler uncaughtExceptionHandler() {
return Optional
.ofNullable(Thread.currentThread().getUncaughtExceptionHandler())
.orElse(NoOp.uncaughtExceptionHandler());
}
public static void report(@Nonnull final Object err) {
uncaughtExceptionHandler().uncaughtException(Thread.currentThread(), toThrowable(err));
}
public static void forever(@Nonnull final ThrowingRunnable runnable) {
forever(uncaughtExceptionHandler(), runnable);
}
public static void forever(
@Nonnull final Thread.UncaughtExceptionHandler exceptionHandler,
@Nonnull final ThrowingRunnable runnable
) {
while (!Thread.currentThread().isInterrupted()) {
try {
runnable.execute();
} catch (final InterruptedException exc) {
return;
} catch (final Exception exc) {
exceptionHandler.uncaughtException(Thread.currentThread(), exc);
}
}
}
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
public static boolean wait(final Object monitor) {
while (!Thread.currentThread().isInterrupted()) {
try {
synchronized (monitor) {
monitor.wait();
}
} catch (final InterruptedException exc) {
return false;
}
}
return true;
}
public static void sleep(final Duration duration) {
final long started = System.nanoTime();
do {
try {
Thread.sleep(duration.toMillis());
return;
} catch (final InterruptedException ignore) {
}
} while ((System.nanoTime() - started) < duration.toNanos());
}
public static void parallel(@Nonnull final Executor executor, @Nonnull final ThrowingRunnable... runnables)
throws ParallelExecutionException {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(runnables, "nullables must not be null");
final Semaphore semaphore = new Semaphore(0);
final List exceptions = Collections.synchronizedList(new ArrayList());
for (final ThrowingRunnable runnable : runnables) {
executor.execute(() -> {
try {
runnable.run();
} catch (final Exception exc) {
exceptions.add(exc);
} finally {
semaphore.release(1);
}
});
}
semaphore.acquireUninterruptibly(runnables.length);
if (!exceptions.isEmpty()) {
throw new ParallelExecutionException(Seq.ofCollection(exceptions));
}
}
@SuppressWarnings("unchecked")
@SafeVarargs
public static Seq parallel(final @Nonnull Executor executor, final @Nonnull Callable extends T>... runnables)
throws ParallelExecutionException {
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(runnables, "nullables must not be null");
final Promise[] promises = new Promise[runnables.length];
int i = 0;
for (final Callable extends T> runnable : runnables) {
final Promise promise = Promise.promise();
promises[i++] = promise;
executor.execute(() -> {
try {
final T result = runnable.call();
promise.fulfill(result);
} catch (final Exception exc) {
promise.fail(exc);
}
});
}
final SeqBuilder results = Seq.builder();
final SeqBuilder exceptions = Seq.builder();
for (final Promise promise : promises) {
promise.waitFor();
if (promise.isSuccess()) {
results.add((T) promise.get());
} else {
exceptions.add(promise.getException());
}
}
if (exceptions.isEmpty()) {
return results.build();
}
throw new ParallelExecutionException(exceptions.result());
}
@SafeVarargs
public static ThrowingConsumer>> parallel(@Nonnull final ThrowingConsumer>... actions) {
return (callback) -> {
final boolean[] hasResult = new boolean[actions.length];
final Object[] results = new Object[actions.length];
final Object[] errors = new Object[actions.length];
final AtomicInteger outstanding = new AtomicInteger(actions.length);
final Function> cb = (ix) -> (err, res) -> {
synchronized (actions[ix]) {
if (hasResult[ix]) {
report(new TaskCompletedMoreThanOnceException(actions[ix], errors[ix], results[ix], err, res));
return;
}
hasResult[ix] = true;
}
errors[ix] = err;
results[ix] = res;
if (outstanding.decrementAndGet() == 0) {
final Seq
© 2015 - 2025 Weber Informatics LLC | Privacy Policy