summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils
diff options
context:
space:
mode:
Diffstat (limited to 'base/src/main/java/bjc/utils')
-rw-r--r--base/src/main/java/bjc/utils/funcutils/Callables.java60
-rw-r--r--base/src/main/java/bjc/utils/funcutils/ChainIterator.java54
-rw-r--r--base/src/main/java/bjc/utils/funcutils/FuncUtils.java34
-rw-r--r--base/src/main/java/bjc/utils/funcutils/Isomorphism.java59
-rw-r--r--base/src/main/java/bjc/utils/funcutils/IteratorUtils.java102
-rw-r--r--base/src/main/java/bjc/utils/funcutils/QueueBackedIterator.java36
-rw-r--r--base/src/main/java/bjc/utils/funcutils/Strategy.java81
-rw-r--r--base/src/main/java/bjc/utils/patterns/ComplexPattern.java90
-rw-r--r--base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java13
-rw-r--r--base/src/main/java/bjc/utils/patterns/Pattern.java6
10 files changed, 376 insertions, 159 deletions
diff --git a/base/src/main/java/bjc/utils/funcutils/Callables.java b/base/src/main/java/bjc/utils/funcutils/Callables.java
new file mode 100644
index 0000000..5895347
--- /dev/null
+++ b/base/src/main/java/bjc/utils/funcutils/Callables.java
@@ -0,0 +1,60 @@
+package bjc.utils.funcutils;
+
+import java.util.concurrent.*;
+import java.util.function.*;
+
+/**
+ * Utility function for dealing with callables and other things.
+ *
+ * @author Ben Culkin
+ *
+ */
+public class Callables
+{
+ /**
+ * Perform a 'bind' that appends a function to a callable.
+ *
+ * @param <Input> The type originally returned by the callable.
+ * @param <Output> The type returned by the function.
+ *
+ * @param call The original callable.
+ * @param func The function to use to transform the result.
+ *
+ * @return A callable which applies the given function to the result of them.
+ */
+ public static <Input, Output> Callable<Output> bind(
+ Callable<Input> call, Function<Input, Callable<Output>> func)
+ {
+ return () -> func.apply(call.call()).call();
+ }
+
+ /**
+ * Convert a normal function to a function on callables.
+ *
+ * @param <Input> The input to the function.
+ * @param <Output> The output from the function.
+ *
+ * @param func The function to convert.
+ *
+ * @return The function, made to work over callables.
+ */
+ public static <Input, Output> Function<Callable<Input>, Callable<Output>>
+ fmap(Function<Input, Output> func)
+ {
+ return (inp) -> () -> func.apply(inp.call());
+ }
+
+ /**
+ * Convert a future into a callable.
+ *
+ * @param <Output> The type returned by the future.
+ *
+ * @param fut The future to convert.
+ *
+ * @return A future which yields that value.
+ */
+ public static <Output> Callable<Output> obtain(Future<Output> fut)
+ {
+ return () -> fut.get();
+ }
+}
diff --git a/base/src/main/java/bjc/utils/funcutils/ChainIterator.java b/base/src/main/java/bjc/utils/funcutils/ChainIterator.java
new file mode 100644
index 0000000..36f94e5
--- /dev/null
+++ b/base/src/main/java/bjc/utils/funcutils/ChainIterator.java
@@ -0,0 +1,54 @@
+package bjc.utils.funcutils;
+
+import java.util.*;
+import java.util.function.*;
+
+/**
+ * A chain iterator. This is essentially flatMap in iterator form.
+ *
+ * @author bjculkin
+ *
+ * @param <T1>
+ * The type of the input values.
+ *
+ * @param <T2>
+ * The type of the output values.
+ */
+public class ChainIterator<T1, T2> implements Iterator<T2> {
+ private Iterator<T1> mainItr;
+ private Function<T1, Iterator<T2>> trans;
+
+ private Iterator<T2> curItr;
+
+ /**
+ * Create a new chain iterator.
+ *
+ * @param mainItr
+ * The main iterator for input.
+ *
+ * @param trans
+ * The transformation to use to produce the outputs.
+ */
+ public ChainIterator(Iterator<T1> mainItr, Function<T1, Iterator<T2>> trans) {
+ this.mainItr = mainItr;
+ this.trans = trans;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (curItr != null) {
+ return curItr.hasNext() ? true : mainItr.hasNext();
+ }
+
+ return mainItr.hasNext();
+ }
+
+ @Override
+ public T2 next() {
+ if (curItr == null || !curItr.hasNext()) {
+ curItr = trans.apply(mainItr.next());
+ }
+
+ return curItr.next();
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/funcutils/FuncUtils.java b/base/src/main/java/bjc/utils/funcutils/FuncUtils.java
index 70e521a..2c65876 100644
--- a/base/src/main/java/bjc/utils/funcutils/FuncUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/FuncUtils.java
@@ -29,9 +29,12 @@ public class FuncUtils {
*
* @return The function transformed into a unary function returning a function.
*/
- public static <A, B, C> Function<A, Function<B, C>>
- curry2(final BiFunction<A, B, C> func) {
- return arg1 -> arg2 -> func.apply(arg1, arg2);
+ public static <A, B, C> Function<A, Function<B, C>> curry2(
+ final BiFunction<A, B, C> func)
+ {
+ return arg1 ->
+ arg2 ->
+ func.apply(arg1, arg2);
}
/**
@@ -43,14 +46,17 @@ public class FuncUtils {
* @param cons
* The action to perform.
*/
- public static void doTimes(final int nTimes, final Consumer<Integer> cons) {
- for (int i = 0; i < nTimes; i++) {
- cons.accept(i);
- }
+ public static void doTimes(
+ final int nTimes,
+ final Consumer<Integer> cons)
+ {
+ for (int i = 0; i < nTimes; i++) cons.accept(i);
}
/**
* Return an operator that executes until it converges.
+ *
+ * @param <T> The type the operator is on.
*
* @param op
* The operator to execute.
@@ -62,12 +68,15 @@ public class FuncUtils {
* @return The requested operator.
*/
public static <T> UnaryOperator<T> converge(final UnaryOperator<T> op,
- final int maxTries) {
+ final int maxTries)
+ {
return converge(op, Object::equals, maxTries);
}
/**
* Return an operator that executes until it converges.
+ *
+ * @param <T> The type the operator is on.
*
* @param op
* The operator to execute.
@@ -81,11 +90,14 @@ public class FuncUtils {
*
* @return The requested operator.
*/
- public static <T> UnaryOperator<T> converge(final UnaryOperator<T> op,
- final BiPredicate<T, T> converged, final int maxTries) {
+ public static <T> UnaryOperator<T> converge(
+ final UnaryOperator<T> op,
+ final BiPredicate<T, T> converged,
+ final int maxTries)
+ {
return val -> {
T newVal = op.apply(val);
- T oldVal;
+ T oldVal = newVal;
int tries = 0;
diff --git a/base/src/main/java/bjc/utils/funcutils/Isomorphism.java b/base/src/main/java/bjc/utils/funcutils/Isomorphism.java
deleted file mode 100644
index c219d7f..0000000
--- a/base/src/main/java/bjc/utils/funcutils/Isomorphism.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package bjc.utils.funcutils;
-
-import java.util.function.Function;
-
-/**
- * A pair of functions to transform between a pair of types.
- *
- * @author bjculkin
- *
- * @param <S>
- * The source type of the isomorphism.
- *
- * @param <D>
- * The destination type of isomorphism.
- */
-public class Isomorphism<S, D> {
- /* The function to the destination type. */
- private Function<S, D> toFunc;
- /* The function to the source type. */
- private Function<D, S> fromFunc;
-
- /**
- * Create a new isomorphism.
- *
- * @param to
- * The 'forward' function, from the source to the definition.
- *
- * @param from
- * The 'backward' function, from the definition to the source.
- */
- public Isomorphism(Function<S, D> to, Function<D, S> from) {
- toFunc = to;
- fromFunc = from;
- }
-
- /**
- * Apply the isomorphism forward.
- *
- * @param val
- * The source value.
- *
- * @return The destination value.
- */
- public D to(S val) {
- return toFunc.apply(val);
- }
-
- /**
- * Apply the isomorphism backward.
- *
- * @param val
- * The destination value.
- *
- * @return The source value.
- */
- public S from(D val) {
- return fromFunc.apply(val);
- }
-}
diff --git a/base/src/main/java/bjc/utils/funcutils/IteratorUtils.java b/base/src/main/java/bjc/utils/funcutils/IteratorUtils.java
index 8d51996..ea67295 100644
--- a/base/src/main/java/bjc/utils/funcutils/IteratorUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/IteratorUtils.java
@@ -3,7 +3,7 @@ package bjc.utils.funcutils;
import java.util.*;
import java.util.function.*;
-import bjc.data.ArrayIterator;
+import bjc.data.*;
/**
* Utility methods for dealing with iterators.
@@ -13,57 +13,9 @@ import bjc.data.ArrayIterator;
*/
public class IteratorUtils {
/**
- * A chain iterator. This is essentially flatMap in iterator form.
- *
- * @author bjculkin
- *
- * @param <T1>
- * The type of the input values.
- *
- * @param <T2>
- * The type of the output values.
- */
- public static class ChainIterator<T1, T2> implements Iterator<T2> {
- private Iterator<T1> mainItr;
- private Function<T1, Iterator<T2>> trans;
-
- private Iterator<T2> curItr;
-
- /**
- * Create a new chain iterator.
- *
- * @param mainItr
- * The main iterator for input.
- *
- * @param trans
- * The transformation to use to produce the outputs.
- */
- public ChainIterator(Iterator<T1> mainItr, Function<T1, Iterator<T2>> trans) {
- this.mainItr = mainItr;
- this.trans = trans;
- }
-
- @Override
- public boolean hasNext() {
- if (curItr != null) {
- return curItr.hasNext() ? true : mainItr.hasNext();
- }
-
- return mainItr.hasNext();
- }
-
- @Override
- public T2 next() {
- if (curItr == null || !curItr.hasNext()) {
- curItr = trans.apply(mainItr.next());
- }
-
- return curItr.next();
- }
- }
-
- /**
* Convert an iterator to an iterable.
+ *
+ * @param <E> The type being iterated over.
*
* @param itr
* The iterator to convert.
@@ -77,6 +29,8 @@ public class IteratorUtils {
/**
* Convert an iterable to an iterator.
*
+ * @param <E> The type being iterated over.
+ *
* @param itr
* The iterable to convert.
*
@@ -89,18 +43,23 @@ public class IteratorUtils {
/**
* Convert an array to an iterator.
*
+ * @param <E> The type being iterated over.
+ *
* @param parms
* The array to iterate over.
*
* @return An iterator over the provided array.
*/
@SafeVarargs
- public static <E> Iterator<E> AI(E... parms) {
+ public static <E> Iterator<E> I(E... parms) {
return new ArrayIterator<>(parms);
}
/**
* Create a chain iterator.
+ *
+ * @param <A> The initial type being iterated over.
+ * @param <B> The resulting type being iterated over.
*
* @param itrA
* The iterator for input values.
@@ -114,4 +73,43 @@ public class IteratorUtils {
Function<A, Iterator<B>> itrB) {
return new ChainIterator<>(itrA, itrB);
}
+
+ /**
+ * Perform a left-fold over an iterator.
+ *
+ * @param <ElementType> The type of elements in the iterator.
+ * @param <ResultType> The result from the fold.
+ *
+ * @param itr The items to iterate over.
+ * @param zero The initial element for the fold.
+ * @param folder The function that does the folding.
+ *
+ * @return The result of folding over the iterator.
+ */
+ public static <ElementType, ResultType> ResultType foldLeft(
+ Iterable<ElementType> itr,
+ ResultType zero,
+ BiFunction<ElementType, ResultType, ResultType> folder)
+ {
+ ResultType state = zero;
+ for (ElementType elem : itr) {
+ state = folder.apply(elem, state);
+ }
+ return state;
+ }
+
+ /**
+ * Creates an 'entangled' pair of a consumer and an iterator.
+ *
+ * @param <ElementType> The type of value involved.
+ *
+ * @return A pair consisting of a consumer of values, and an iterator that
+ * yields the consumed values.
+ */
+ public static <ElementType>
+ IPair<Consumer<ElementType>, Iterator<ElementType>> entangle()
+ {
+ Queue<ElementType> backer = new ArrayDeque<>();
+ return IPair.pair(backer::add, new QueueBackedIterator<>(backer));
+ }
}
diff --git a/base/src/main/java/bjc/utils/funcutils/QueueBackedIterator.java b/base/src/main/java/bjc/utils/funcutils/QueueBackedIterator.java
new file mode 100644
index 0000000..8b9f401
--- /dev/null
+++ b/base/src/main/java/bjc/utils/funcutils/QueueBackedIterator.java
@@ -0,0 +1,36 @@
+package bjc.utils.funcutils;
+
+import java.util.*;
+
+/**
+ * An iterator backed by a queue.
+ *
+ * @author Ben Culkin
+ *
+ * @param <ElementType> The type of element
+ */
+public class QueueBackedIterator<ElementType>
+ implements Iterator<ElementType>
+{
+ private final Queue<ElementType> backer;
+
+ /**
+ * Create a new queue-backed iterator.
+ *
+ * @param backer The queue which backs this iterator.
+ */
+ public QueueBackedIterator(Queue<ElementType> backer)
+ {
+ this.backer = backer;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return !backer.isEmpty();
+ }
+
+ @Override
+ public ElementType next() {
+ return backer.remove();
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/funcutils/Strategy.java b/base/src/main/java/bjc/utils/funcutils/Strategy.java
new file mode 100644
index 0000000..316879f
--- /dev/null
+++ b/base/src/main/java/bjc/utils/funcutils/Strategy.java
@@ -0,0 +1,81 @@
+package bjc.utils.funcutils;
+
+import java.util.concurrent.*;
+import java.util.function.*;
+
+/**
+ * Strategy for dealing with parallel execution.
+ *
+ * @author Ben Culkin
+ *
+ * @param <Output> The type returned by the tasks.
+ *
+ */
+public interface Strategy<Output> extends Function<Callable<Output>, Future<Output>>
+{
+ /**
+ * Convert a function into one which operates concurrently, using this strategy.
+ *
+ * @param <Input> The type of the function argument.
+ *
+ * @param func The type of the function.
+ *
+ * @return A function which executes concurrently.
+ */
+ public default <Input> Function<Input, Future<Output>> using(Function<Input, Output> func)
+ {
+ return (input) -> this.apply(() -> func.apply(input));
+ }
+
+ /**
+ * A strategy which will run tasks in serial.
+ *
+ * @param <Output> The type returned by the task.
+ *
+ * @return A strategy which executes things serially.
+ */
+ public static <Output> Strategy<Output> serial()
+ {
+ return (call) -> {
+ FutureTask<Output> task = new FutureTask<>(call);
+ task.run();
+ return task;
+ };
+ }
+ /**
+ * A strategy which creates a fresh thread to execute a task on.
+ *
+ * @param <Output> The type returned by the task.
+ *
+ * @return A strategy which uses threads to create tasks.
+ */
+ public static <Output> Strategy<Output> simpleThread()
+ {
+ // I leave this as an example as of what is possible with combinators.
+ // return (call) -> invoke(introducing(
+ // () -> new FutureTask<>(call),
+ // (task, input) -> doWith(
+ // (FutureTask<Output> tsk) ->
+ // new Thread(task).start()).apply(task)
+ // ));
+ return (call) -> {
+ FutureTask<Output> task = new FutureTask<>(call);
+ new Thread(task).start();
+ return task;
+ };
+ }
+
+ /**
+ * A strategy that uses an executor service.
+ *
+ * @param <Output> The type returned by the task.
+ *
+ * @param svc The executor service to use.
+ *
+ * @return A strategy which uses the provided executor.
+ */
+ public static <Output> Strategy<Output> executorService(ExecutorService svc)
+ {
+ return svc::submit;
+ }
+}
diff --git a/base/src/main/java/bjc/utils/patterns/ComplexPattern.java b/base/src/main/java/bjc/utils/patterns/ComplexPattern.java
index 3926f2c..e9035df 100644
--- a/base/src/main/java/bjc/utils/patterns/ComplexPattern.java
+++ b/base/src/main/java/bjc/utils/patterns/ComplexPattern.java
@@ -35,6 +35,8 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
*/
ReturnType apply(InputType input, PredType state);
+ /* Pattern producing functions */
+
/**
* Create a pattern composed from a predicate & a function.
*
@@ -49,7 +51,8 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
*/
static <RetType, PreType, InpType> ComplexPattern<RetType, PreType, InpType> from(
Function<InpType, IPair<Boolean, PreType>> matcher,
- BiFunction<InpType, PreType, RetType> accepter) {
+ BiFunction<InpType, PreType, RetType> accepter)
+ {
return new FunctionalPattern<>(matcher, accepter);
}
@@ -68,7 +71,8 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
@SuppressWarnings("unchecked")
static <ClassType, RetType, InpType> ComplexPattern<RetType, ?, InpType> ofClass(
Class<ClassType> clasz,
- Function<ClassType, RetType> action) {
+ Function<ClassType, RetType> action)
+ {
return from(
(input) -> IPair.pair(clasz.isInstance(input), null),
(input, ignored) -> action.apply((ClassType)input)
@@ -89,11 +93,12 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
static <RetType, InpType> ComplexPattern<RetType, ?, InpType> matchesObject(
InpType obj,
Function<InpType, RetType> action
- ) {
+ )
+ {
return from(
- (input) -> IPair.pair(obj.equals(input), null),
- (input, ignored) -> action.apply(input)
- );
+ (input) -> IPair.pair(obj.equals(input), null),
+ (input, ignored) -> action.apply(input)
+ );
}
/**
@@ -113,13 +118,16 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
static <RetType, InpType> ComplexPattern<RetType, ?, InpType> equalsString(
String pattern,
BiFunction<InpType, String, RetType> action
- ) {
+ )
+ {
+ Function<InpType, IPair<Boolean, String>> matcher = (input) -> {
+ String objString = input.toString();
+
+ return IPair.pair(pattern.equals(objString), objString);
+ };
+
return from(
- (input) -> {
- String objString = input.toString();
-
- return IPair.pair(pattern.equals(objString), objString);
- },
+ matcher,
(input, objString) -> action.apply(input, objString)
);
}
@@ -140,21 +148,21 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
String regex,
Predicate<Matcher> cond,
BiFunction<InpType, Matcher, RetType> action
- ) {
+ )
+ {
java.util.regex.Pattern regexPat = java.util.regex.Pattern.compile(regex);
+ Function<InpType, IPair<Boolean, Matcher>> matcher = (input) -> {
+ String inpString = input.toString();
+
+ Matcher mat = regexPat.matcher(inpString);
+
+ if (cond.test(mat)) return IPair.pair(true, mat);
+ else return IPair.pair(false, null);
+ };
+
return from(
- (input) -> {
- String inpString = input.toString();
-
- Matcher mat = regexPat.matcher(inpString);
-
- if (cond.test(mat)) {
- return IPair.pair(true, mat);
- } else {
- return IPair.pair(false, null);
- }
- },
+ matcher,
(input, res) -> action.apply(input, res)
);
}
@@ -162,6 +170,7 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
// @TODO Nov 21, 2020 Ben Culkin :MorePatterns
// Try and write something to iterate over Iterator in a type-safe manner
// Also, something for doing a sub-pattern match
+
/**
* Create a pattern which will always execute.
*
@@ -174,10 +183,41 @@ public interface ComplexPattern<ReturnType, PredType, InputType> {
*/
static <RetType, InpType> ComplexPattern<RetType, ?, InpType> otherwise(
Function<InpType, RetType> action
- ) {
+ )
+ {
return from(
(input) -> IPair.pair(true, null),
(input, ignored) -> action.apply(input)
);
}
+
+ /**
+ * Create a pattern which checks if the string form of a given object starts
+ * with a specific string.
+ *
+ * @param <RetType> The type returned by the matcher.
+ * @param <InpType> The type being matched against.
+ *
+ * @param pattern The string to check against.
+ * @param action The action to execute.
+ *
+ * @return A pattern which functions as described.
+ */
+ static <RetType, InpType> ComplexPattern<RetType, String, InpType> startsWith(
+ String pattern,
+ Function<String, RetType> action)
+ {
+ return from((input) -> {
+ String objString = input.toString();
+
+ if (objString.startsWith(pattern)) {
+ return IPair.pair(
+ true,
+ objString.substring(
+ pattern.length()));
+ } else {
+ return IPair.pair(false, null);
+ }
+ }, (ignored, input) -> action.apply(input));
+ }
} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java b/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java
index 7900262..8e040fe 100644
--- a/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java
+++ b/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java
@@ -13,9 +13,10 @@ import bjc.data.*;
* @author Ben Culkin
*
* @param <ReturnType> The type returned by the pattern matcher.
+ * @param <InputType> The type of the input to match against.
*/
public class MutablePatternMatcher<ReturnType, InputType>
- implements IPatternMatcher<ReturnType, InputType>{
+ implements IPatternMatcher<ReturnType, InputType> {
private final List<ComplexPattern<ReturnType, Object, InputType>> patterns;
/**
@@ -45,15 +46,15 @@ public class MutablePatternMatcher<ReturnType, InputType>
@Override
public ReturnType matchFor(InputType input) throws NonExhaustiveMatch {
Iterator<ComplexPattern<ReturnType, Object, InputType>> iterator;
- for (iterator = new NonCMEIterator<>(patterns);
- iterator.hasNext();) {
+ iterator = new NonCMEIterator<>(patterns);
+ while(iterator.hasNext()) {
ComplexPattern<ReturnType, Object, InputType> pattern = iterator.next();
IPair<Boolean, Object> matches = pattern.matches(input);
- if (matches.getLeft()) {
- pattern.apply(input, matches.getRight());
- }
+ matches.doWith((bool, obj) -> {
+ if (bool) pattern.apply(input, obj);
+ });
}
throw new NonExhaustiveMatch("Non-exhaustive match against " + input);
diff --git a/base/src/main/java/bjc/utils/patterns/Pattern.java b/base/src/main/java/bjc/utils/patterns/Pattern.java
index e03623e..c9902e8 100644
--- a/base/src/main/java/bjc/utils/patterns/Pattern.java
+++ b/base/src/main/java/bjc/utils/patterns/Pattern.java
@@ -1,11 +1,5 @@
package bjc.utils.patterns;
-import java.util.*;
-import java.util.function.*;
-import java.util.regex.*;
-
-import bjc.data.*;
-
/**
* A simpler version of ComplexPattern, which always applies against Object
*