summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/funcutils
diff options
context:
space:
mode:
Diffstat (limited to 'base/src/main/java/bjc/utils/funcutils')
-rw-r--r--base/src/main/java/bjc/utils/funcutils/Builder.java (renamed from base/src/main/java/bjc/utils/funcutils/IBuilder.java)2
-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/CollectorUtils.java8
-rw-r--r--base/src/main/java/bjc/utils/funcutils/CompoundCollector.java22
-rw-r--r--base/src/main/java/bjc/utils/funcutils/EnumUtils.java4
-rw-r--r--base/src/main/java/bjc/utils/funcutils/FuncUtils.java34
-rw-r--r--base/src/main/java/bjc/utils/funcutils/GroupPartIteration.java86
-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/LambdaLock.java12
-rw-r--r--base/src/main/java/bjc/utils/funcutils/ListUtils.java177
-rw-r--r--base/src/main/java/bjc/utils/funcutils/QueueBackedIterator.java36
-rw-r--r--base/src/main/java/bjc/utils/funcutils/SetUtils.java12
-rw-r--r--base/src/main/java/bjc/utils/funcutils/Strategy.java81
-rw-r--r--base/src/main/java/bjc/utils/funcutils/StringUtils.java249
-rw-r--r--base/src/main/java/bjc/utils/funcutils/TestUtils.java31
-rw-r--r--base/src/main/java/bjc/utils/funcutils/TreeUtils.java67
18 files changed, 583 insertions, 513 deletions
diff --git a/base/src/main/java/bjc/utils/funcutils/IBuilder.java b/base/src/main/java/bjc/utils/funcutils/Builder.java
index b1a2020..72c045d 100644
--- a/base/src/main/java/bjc/utils/funcutils/IBuilder.java
+++ b/base/src/main/java/bjc/utils/funcutils/Builder.java
@@ -8,7 +8,7 @@ package bjc.utils.funcutils;
* @param <E>
* The type of object being built.
*/
-public interface IBuilder<E> {
+public interface Builder<E> {
/**
* Build the object this builder is building.
*
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/CollectorUtils.java b/base/src/main/java/bjc/utils/funcutils/CollectorUtils.java
index 81313c8..a92c2d1 100644
--- a/base/src/main/java/bjc/utils/funcutils/CollectorUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/CollectorUtils.java
@@ -2,8 +2,8 @@ package bjc.utils.funcutils;
import java.util.stream.Collector;
-import bjc.data.IHolder;
-import bjc.data.IPair;
+import bjc.data.Holder;
+import bjc.data.Pair;
/**
* Utilities for producing implementations of {@link Collector}
@@ -38,8 +38,8 @@ public class CollectorUtils {
* @return A collector that functions as mentioned above.
*/
public static <InitialType, AuxType1, AuxType2, FinalType1, FinalType2>
- Collector<InitialType, IHolder<IPair<AuxType1, AuxType2>>,
- IPair<FinalType1, FinalType2>>
+ Collector<InitialType, Holder<Pair<AuxType1, AuxType2>>,
+ Pair<FinalType1, FinalType2>>
compoundCollect(final Collector<InitialType, AuxType1, FinalType1> first,
final Collector<InitialType, AuxType2, FinalType2> second) {
return new CompoundCollector<>(first, second);
diff --git a/base/src/main/java/bjc/utils/funcutils/CompoundCollector.java b/base/src/main/java/bjc/utils/funcutils/CompoundCollector.java
index 5e51c20..5aa266e 100644
--- a/base/src/main/java/bjc/utils/funcutils/CompoundCollector.java
+++ b/base/src/main/java/bjc/utils/funcutils/CompoundCollector.java
@@ -7,10 +7,10 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
-import bjc.data.IHolder;
-import bjc.data.IPair;
-import bjc.data.Identity;
+import bjc.data.Holder;
import bjc.data.Pair;
+import bjc.data.Identity;
+import bjc.data.SimplePair;
/**
* Implementation of a collecter that uses two collectors.
@@ -18,8 +18,8 @@ import bjc.data.Pair;
* @author Ben Culkin
*/
final class CompoundCollector<InitialType, AuxType1, AuxType2, FinalType1, FinalType2>
- implements Collector<InitialType, IHolder<IPair<AuxType1, AuxType2>>,
- IPair<FinalType1, FinalType2>> {
+ implements Collector<InitialType, Holder<Pair<AuxType1, AuxType2>>,
+ Pair<FinalType1, FinalType2>> {
/* Our characteristics. */
private final Set<java.util.stream.Collector.Characteristics> characteristicSet;
@@ -48,7 +48,7 @@ final class CompoundCollector<InitialType, AuxType1, AuxType2, FinalType1, Final
}
@Override
- public BiConsumer<IHolder<IPair<AuxType1, AuxType2>>, InitialType> accumulator() {
+ public BiConsumer<Holder<Pair<AuxType1, AuxType2>>, InitialType> accumulator() {
final BiConsumer<AuxType1, InitialType> firstAccumulator = first.accumulator();
final BiConsumer<AuxType2, InitialType> secondAccumulator = second.accumulator();
@@ -68,7 +68,7 @@ final class CompoundCollector<InitialType, AuxType1, AuxType2, FinalType1, Final
}
@Override
- public BinaryOperator<IHolder<IPair<AuxType1, AuxType2>>> combiner() {
+ public BinaryOperator<Holder<Pair<AuxType1, AuxType2>>> combiner() {
final BinaryOperator<AuxType1> firstCombiner = first.combiner();
final BinaryOperator<AuxType2> secondCombiner = second.combiner();
@@ -80,25 +80,25 @@ final class CompoundCollector<InitialType, AuxType1, AuxType2, FinalType1, Final
}
@Override
- public Function<IHolder<IPair<AuxType1, AuxType2>>, IPair<FinalType1, FinalType2>>
+ public Function<Holder<Pair<AuxType1, AuxType2>>, Pair<FinalType1, FinalType2>>
finisher() {
return state -> state.unwrap(pair -> {
return pair.bind((left, right) -> {
final FinalType1 finalLeft = first.finisher().apply(left);
final FinalType2 finalRight = second.finisher().apply(right);
- return new Pair<>(finalLeft, finalRight);
+ return new SimplePair<>(finalLeft, finalRight);
});
});
}
@Override
- public Supplier<IHolder<IPair<AuxType1, AuxType2>>> supplier() {
+ public Supplier<Holder<Pair<AuxType1, AuxType2>>> supplier() {
return () -> {
final AuxType1 initialLeft = first.supplier().get();
final AuxType2 initialRight = second.supplier().get();
- return new Identity<>(new Pair<>(initialLeft, initialRight));
+ return new Identity<>(new SimplePair<>(initialLeft, initialRight));
};
}
}
diff --git a/base/src/main/java/bjc/utils/funcutils/EnumUtils.java b/base/src/main/java/bjc/utils/funcutils/EnumUtils.java
index e8898ca..6d53952 100644
--- a/base/src/main/java/bjc/utils/funcutils/EnumUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/EnumUtils.java
@@ -4,7 +4,7 @@ import java.util.Random;
import java.util.function.Consumer;
import bjc.funcdata.FunctionalList;
-import bjc.funcdata.IList;
+import bjc.funcdata.ListEx;
/**
* Utility methods on enums.
@@ -34,7 +34,7 @@ public class EnumUtils {
final int nValues, final Consumer<E> action, final Random rnd) {
final E[] enumValues = clasz.getEnumConstants();
- final IList<E> valueList = new FunctionalList<>(enumValues);
+ final ListEx<E> valueList = new FunctionalList<>(enumValues);
final int randomValueCount = enumValues.length - nValues;
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/GroupPartIteration.java b/base/src/main/java/bjc/utils/funcutils/GroupPartIteration.java
deleted file mode 100644
index 681d707..0000000
--- a/base/src/main/java/bjc/utils/funcutils/GroupPartIteration.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package bjc.utils.funcutils;
-
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-import bjc.funcdata.FunctionalList;
-import bjc.funcdata.IList;
-
-/**
- * Implements a single group partitioning pass on a list.
- *
- * @author ben
- *
- * @param <E>
- * The type of element in the list being partitioned
- */
-final class GroupPartIteration<E> implements Consumer<E> {
- /* The list we're returning. */
- private final IList<IList<E>> returnedList;
-
- /* The current partition of the list. */
- public IList<E> currentPartition;
- /* The items rejected from the current partition. */
- private final IList<E> rejectedItems;
-
- /* The number of items in the current partition. */
- private int numberInCurrentPartition;
- /* The number of items in each partition. */
- private final int numberPerPartition;
-
- /* The function to use to count an item. */
- private final Function<E, Integer> elementCounter;
-
- /**
- * Create a new group partitioning iteration.
- *
- * @param returned
- * The list containing all of the existing partitions.
- *
- * @param rejects
- * The items that have been rejected from a partition for being
- * too large.
- *
- * @param nPerPart
- * The combined value of items that should go into each
- * partition.
- *
- * @param eleCount
- * The function to use to determine the value of an item.
- */
- public GroupPartIteration(final IList<IList<E>> returned, final IList<E> rejects,
- final int nPerPart, final Function<E, Integer> eleCount) {
- this.returnedList = returned;
- this.rejectedItems = rejects;
- this.numberPerPartition = nPerPart;
- this.elementCounter = eleCount;
-
- this.currentPartition = new FunctionalList<>();
- this.numberInCurrentPartition = 0;
- }
-
- @Override
- public void accept(final E value) {
- final boolean shouldStartPartition
- = numberInCurrentPartition >= numberPerPartition;
-
- if (shouldStartPartition) {
- returnedList.add(currentPartition);
-
- currentPartition = new FunctionalList<>();
- numberInCurrentPartition = 0;
- } else {
- final int currentElementCount = elementCounter.apply(value);
-
- final boolean shouldReject = (numberInCurrentPartition + currentElementCount)
- >= numberPerPartition;
-
- if (shouldReject) {
- rejectedItems.add(value);
- } else {
- currentPartition.add(value);
- numberInCurrentPartition += currentElementCount;
- }
- }
- }
-}
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..662b1bf 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>
+ Pair<Consumer<ElementType>, Iterator<ElementType>> entangle()
+ {
+ Queue<ElementType> backer = new ArrayDeque<>();
+ return Pair.pair(backer::add, new QueueBackedIterator<>(backer));
+ }
}
diff --git a/base/src/main/java/bjc/utils/funcutils/LambdaLock.java b/base/src/main/java/bjc/utils/funcutils/LambdaLock.java
index f3637f9..c7ba09a 100644
--- a/base/src/main/java/bjc/utils/funcutils/LambdaLock.java
+++ b/base/src/main/java/bjc/utils/funcutils/LambdaLock.java
@@ -36,8 +36,9 @@ public class LambdaLock {
/**
* Execute an action with the read lock taken.
*
- * @param supp
- * The action to call.
+ * @param <T> The type returned by the action.
+ *
+ * @param supp The action to call.
*
* @return The result of the action.
*/
@@ -53,9 +54,10 @@ public class LambdaLock {
/**
* Execute an action with the write lock taken.
- *
- * @param supp
- * The action to call.
+ *
+ * @param <T> The type returned by the action.
+ *
+ * @param supp The action to call.
*
* @return The result of the action.
*/
diff --git a/base/src/main/java/bjc/utils/funcutils/ListUtils.java b/base/src/main/java/bjc/utils/funcutils/ListUtils.java
index f689d6c..ab32ccc 100644
--- a/base/src/main/java/bjc/utils/funcutils/ListUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/ListUtils.java
@@ -1,14 +1,10 @@
package bjc.utils.funcutils;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.Function;
-import java.util.function.Supplier;
+import java.util.*;
+import java.util.function.*;
import bjc.funcdata.FunctionalList;
-import bjc.funcdata.IList;
+import bjc.funcdata.ListEx;
/**
* Utilities for manipulating FunctionalLists and regular Collections lists that
@@ -28,9 +24,8 @@ public class ListUtils {
*
* @return The collapsed string of tokens.
*/
- public static String collapseTokens(final IList<String> input) {
- if (input == null)
- throw new NullPointerException("Input must not be null");
+ public static String collapseTokens(final ListEx<String> input) {
+ if (input == null) throw new NullPointerException("Input must not be null");
return collapseTokens(input, "");
}
@@ -47,13 +42,10 @@ public class ListUtils {
*
* @return The collapsed string of tokens.
*/
- public static String collapseTokens(final IList<String> input,
+ public static String collapseTokens(final ListEx<String> input,
final String seperator) {
- if (input == null) {
- throw new NullPointerException("Input must not be null");
- } else if (seperator == null) {
- throw new NullPointerException("Seperator must not be null");
- }
+ if (input == null) throw new NullPointerException("Input must not be null");
+ else if (seperator == null) throw new NullPointerException("Seperator must not be null");
if (input.getSize() < 1) {
return "";
@@ -66,9 +58,7 @@ public class ListUtils {
for (final String itm : input.toIterable()) {
state.append(itm);
- if (i != input.getSize()) {
- state.append(seperator);
- }
+ if (i != input.getSize()) state.append(seperator);
i += 1;
}
@@ -96,9 +86,9 @@ public class ListUtils {
* @return A new list containing the desired number of items randomly selected
* from the specified list without replacement.
*/
- public static <E> IList<E> drawWithoutReplacement(final IList<E> list,
+ public static <E> ListEx<E> drawWithoutReplacement(final ListEx<E> list,
final int number, final Function<Integer, Integer> rng) {
- final IList<E> selected = new FunctionalList<>(new ArrayList<>(number));
+ final ListEx<E> selected = new FunctionalList<>(new ArrayList<>(number));
final int total = list.getSize();
@@ -140,13 +130,11 @@ public class ListUtils {
* @return A new list containing the desired number of items randomly selected
* from the specified list.
*/
- public static <E> IList<E> drawWithReplacement(final IList<E> list, final int number,
+ public static <E> ListEx<E> drawWithReplacement(final ListEx<E> list, final int number,
final Function<Integer, Integer> rng) {
- final IList<E> selected = new FunctionalList<>(new ArrayList<>(number));
+ final ListEx<E> selected = new FunctionalList<>(new ArrayList<>(number));
- for (int i = 0; i < number; i++) {
- selected.add(list.randItem(rng));
- }
+ for (int i = 0; i < number; i++) selected.add(list.randItem(rng));
return selected;
}
@@ -170,7 +158,7 @@ public class ListUtils {
*
* @return A list partitioned according to the above rules.
*/
- public static <E> IList<IList<E>> groupPartition(final IList<E> input,
+ public static <E> ListEx<ListEx<E>> groupPartition(final ListEx<E> input,
final Function<E, Integer> counter, final int partitionSize) {
if (input == null) {
throw new NullPointerException("Input list must not be null");
@@ -185,10 +173,10 @@ public class ListUtils {
}
/* List that holds our results. */
- final IList<IList<E>> returned = new FunctionalList<>();
+ final ListEx<ListEx<E>> returned = new FunctionalList<>();
/* List that holds elements rejected during current pass. */
- final IList<E> rejected = new FunctionalList<>();
+ final ListEx<E> rejected = new FunctionalList<>();
final GroupPartIteration<E> it
= new GroupPartIteration<>(returned, rejected, partitionSize, counter);
@@ -199,10 +187,8 @@ public class ListUtils {
numberOfIterations++) {
input.forEach(it);
- if (rejected.isEmpty()) {
- /* Nothing was rejected, so we're done. */
- return returned;
- }
+ /* Nothing was rejected, so we're done. */
+ if (rejected.isEmpty()) return returned;
}
final String fmt
@@ -226,13 +212,11 @@ public class ListUtils {
* @return A list containing all the elements of the lists.
*/
@SafeVarargs
- public static <E> IList<E> mergeLists(final IList<E>... lists) {
- final IList<E> returned = new FunctionalList<>();
+ public static <E> ListEx<E> mergeLists(final ListEx<E>... lists) {
+ final ListEx<E> returned = new FunctionalList<>();
- for (final IList<E> list : lists) {
- for (final E itm : list.toIterable()) {
- returned.add(itm);
- }
+ for (final ListEx<E> list : lists) {
+ for (final E itm : list.toIterable()) returned.add(itm);
}
return returned;
@@ -262,12 +246,12 @@ public class ListUtils {
* If the list couldn't be padded to the
* desired size.
*/
- public static <E> IList<E> padList(final IList<E> list,
+ public static <E> ListEx<E> padList(final ListEx<E> list,
final Function<E, Integer> counter, final int size,
final Supplier<E> padder) {
int count = 0;
- final IList<E> returned = new FunctionalList<>();
+ final ListEx<E> returned = new FunctionalList<>();
for (final E itm : list.toIterable()) {
count += counter.apply(itm);
@@ -334,8 +318,9 @@ public class ListUtils {
*
* This is a version of Algorith P (Plain Changes) from Knuth (vol 4A, pg 322)
*
- * @param list
- * The list to generate permutations from.
+ * @param <T> The type of elements in the list.
+ *
+ * @param list The list to generate permutations from.
* @return The list of permutations of the list.
*/
public static <T> List<List<T>> permuteList(List<T> list) {
@@ -344,9 +329,7 @@ public class ListUtils {
/*
* Special-case small usages.
*/
- if (list.size() == 0) {
- return permutes;
- }
+ if (list.size() == 0) return permutes;
if (list.size() == 1) {
permutes.add(list);
@@ -358,19 +341,8 @@ public class ListUtils {
T elm1 = list.get(0);
T elm2 = list.get(1);
- List<T> currPerm = new ArrayList<>(2);
-
- currPerm.add(elm1);
- currPerm.add(elm2);
-
- permutes.add(currPerm);
-
- currPerm = new ArrayList<>(2);
-
- currPerm.add(elm2);
- currPerm.add(elm1);
-
- permutes.add(currPerm);
+ permutes.add(Arrays.asList(elm1, elm2));
+ permutes.add(Arrays.asList(elm2, elm1));
return permutes;
}
@@ -384,9 +356,7 @@ public class ListUtils {
}
List<T> currentPermute = new ArrayList<>(list.size());
- for (T elm : list) {
- currentPermute.add(elm);
- }
+ for (T elm : list) currentPermute.add(elm);
permutes.add(currentPermute);
int j = list.size() - 1;
@@ -422,9 +392,7 @@ public class ListUtils {
auxC[j] = q;
currentPermute = new ArrayList<>(list.size());
- for (T elm : list) {
- currentPermute.add(elm);
- }
+ for (T elm : list) currentPermute.add(elm);
permutes.add(currentPermute);
j = list.size() - 1;
@@ -441,3 +409,82 @@ public class ListUtils {
list.set(b, tmp);
}
}
+
+/**
+ * Implements a single group partitioning pass on a list.
+ *
+ * @author ben
+ *
+ * @param <E>
+ * The type of element in the list being partitioned
+ */
+class GroupPartIteration<E> implements Consumer<E> {
+ /* The list we're returning. */
+ private final ListEx<ListEx<E>> returnedList;
+
+ /* The current partition of the list. */
+ public ListEx<E> currentPartition;
+ /* The items rejected from the current partition. */
+ private final ListEx<E> rejectedItems;
+
+ /* The number of items in the current partition. */
+ private int numberInCurrentPartition;
+ /* The number of items in each partition. */
+ private final int numberPerPartition;
+
+ /* The function to use to count an item. */
+ private final Function<E, Integer> elementCounter;
+
+ /**
+ * Create a new group partitioning iteration.
+ *
+ * @param returned
+ * The list containing all of the existing partitions.
+ *
+ * @param rejects
+ * The items that have been rejected from a partition for being
+ * too large.
+ *
+ * @param nPerPart
+ * The combined value of items that should go into each
+ * partition.
+ *
+ * @param eleCount
+ * The function to use to determine the value of an item.
+ */
+ public GroupPartIteration(final ListEx<ListEx<E>> returned, final ListEx<E> rejects,
+ final int nPerPart, final Function<E, Integer> eleCount) {
+ this.returnedList = returned;
+ this.rejectedItems = rejects;
+ this.numberPerPartition = nPerPart;
+ this.elementCounter = eleCount;
+
+ this.currentPartition = new FunctionalList<>();
+ this.numberInCurrentPartition = 0;
+ }
+
+ @Override
+ public void accept(final E value) {
+ final boolean shouldStartPartition
+ = numberInCurrentPartition >= numberPerPartition;
+
+ if (shouldStartPartition) {
+ returnedList.add(currentPartition);
+
+ currentPartition = new FunctionalList<>();
+ numberInCurrentPartition = 0;
+ } else {
+ final int currentElementCount = elementCounter.apply(value);
+
+ final boolean shouldReject = (numberInCurrentPartition + currentElementCount)
+ >= numberPerPartition;
+
+ if (shouldReject) {
+ rejectedItems.add(value);
+ } else {
+ currentPartition.add(value);
+ numberInCurrentPartition += currentElementCount;
+ }
+ }
+ }
+}
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/SetUtils.java b/base/src/main/java/bjc/utils/funcutils/SetUtils.java
index 83c191b..b721d10 100644
--- a/base/src/main/java/bjc/utils/funcutils/SetUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/SetUtils.java
@@ -15,8 +15,8 @@ public class SetUtils {
/**
* Create a power-set (set of all subsets) of a given set.
*
- * @param originalSet
- * The set to create a power-set of.
+ * @param <T> The type of elements contained in the set.
+ * @param originalSet The set to create a power-set of.
* @return The power-set of the set.
*/
public static <T> Set<Set<T>> powerSet(Set<T> originalSet) {
@@ -55,17 +55,15 @@ public class SetUtils {
/**
* Utility method for set construction.
*
- * @param elms
- * The elements to stick in the set.
+ * @param <T> The type of elements in the set.
+ * @param elms The elements to stick in the set.
* @return A set containing the specified elements.
*/
@SafeVarargs
public static <T> Set<T> toSet(T... elms) {
Set<T> set = new HashSet<>();
- for (T elm : elms) {
- set.add(elm);
- }
+ for (T elm : elms) set.add(elm);
return set;
}
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/funcutils/StringUtils.java b/base/src/main/java/bjc/utils/funcutils/StringUtils.java
index b7a6835..0b57e18 100644
--- a/base/src/main/java/bjc/utils/funcutils/StringUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/StringUtils.java
@@ -1,79 +1,53 @@
package bjc.utils.funcutils;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Scanner;
-
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ibm.icu.text.BreakIterator;
-import bjc.data.BooleanToggle;
import bjc.utils.ioutils.LevelSplitter;
-import bjc.utils.parserutils.TokenUtils;
-/**
- * Utility methods for operations on strings.
+/** Utility methods for operations on strings.
*
- * @author ben
- */
+ * @author ben */
public class StringUtils {
- /**
- * Check if a string consists only of one or more matches of a regular
+ /**Check if a string consists only of one or more matches of a regular
* expression.
*
- * @param input
- * The string to check.
- *
- * @param rRegex
- * The regex to see if the string only contains matches of.
+ * @param input The string to check.
+ * @param rRegex The regex to see if the string only contains matches of.
*
* @return Whether or not the string consists only of multiple matches of the
* provided regex.
*/
public static boolean containsOnly(final String input, final String rRegex) {
- if (input == null)
- throw new NullPointerException("Input must not be null");
- else if (rRegex == null)
- throw new NullPointerException("Regex must not be null");
+ if (input == null) throw new NullPointerException("Input must not be null");
+ else if (rRegex == null) throw new NullPointerException("Regex must not be null");
- /*
- * This regular expression is fairly simple.
+ /* This regular expression is fairly simple.
*
* First, we match the beginning of the string. Then, we start a non-capturing
* group whose contents are the passed in regex. That group is then matched one
- * or more times and the pattern matches to the end of the string.
- */
+ * or more times and the pattern matches to the end of the string. */
return input.matches("\\A(?:" + rRegex + ")+\\Z");
}
- /**
- * Indent the string being built in a StringBuilder n levels.
- *
- * @param builder
- * The builder to indent in.
+ /** Indent the string being built in a StringBuilder n levels.
*
- * @param levels
- * The number of levels to indent.
+ * @param builder The builder to indent in.
+ * @param levels The number of levels to indent.
*/
public static void indentNLevels(final StringBuilder builder, final int levels) {
- for (int i = 0; i < levels; i++) {
- builder.append("\t");
- }
+ for (int i = 0; i < levels; i++) builder.append("\t");
}
- /**
- * Print out a deque with a special case for easily showing a deque is empty.
- *
- * @param <ContainedType>
- * The type in the deque.
+ /** Print out a deque with a special case for easily showing a deque is empty.
*
- * @param queue
- * The deque to print.
+ * @param <ContainedType> The type in the deque.
*
+ * @param queue The deque to print.
+ *
* @return A string version of the deque, with allowance for an empty deque.
*/
public static <ContainedType> String printDeque(final Deque<ContainedType> queue) {
@@ -83,15 +57,10 @@ public class StringUtils {
/**
* Converts a sequence to an English list.
*
- * @param objects
- * The sequence to convert to an English list.
- *
+ * @param objects The sequence to convert to an English list.
* @param join
- * The string to use for separating the last element from the
- * rest.
- *
- * @param comma
- * The string to use as a comma
+ * The string to use for separating the last element from the rest.
+ * @param comma The string to use as a comma
*
* @return The sequence as an English list.
*/
@@ -140,15 +109,11 @@ public class StringUtils {
return sb.toString();
}
- /**
- * Converts a sequence to an English list.
- *
- * @param objects
- * The sequence to convert to an English list.
+ /** Converts a sequence to an English list.
*
+ * @param objects The sequence to convert to an English list.
* @param join
- * The string to use for separating the last element from the
- * rest.
+ * The string to use for separating the last element from the rest.
*
* @return The sequence as an English list.
*/
@@ -156,30 +121,21 @@ public class StringUtils {
return toEnglishList(objects, join, ",");
}
- /**
- * Converts a sequence to an English list.
- *
- * @param objects
- * The sequence to convert to an English list.
+ /** Converts a sequence to an English list.
*
- * @param and
- * Whether to use 'and' or 'or'.
+ * @param objects The sequence to convert to an English list.
+ * @param and Whether to use 'and' or 'or'.
*
* @return The sequence as an English list.
*/
public static String toEnglishList(final Object[] objects, final boolean and) {
- if (and) {
- return toEnglishList(objects, "and");
- }
-
- return toEnglishList(objects, "or");
+ if (and) return toEnglishList(objects, "and");
+ else return toEnglishList(objects, "or");
}
- /**
- * Count the number of graphemes in a string.
+ /** Count the number of graphemes in a string.
*
- * @param value
- * The string to check.
+ * @param value The string to check.
*
* @return The number of graphemes in the string.
*/
@@ -188,97 +144,57 @@ public class StringUtils {
it.setText(value);
int count = 0;
- while (it.next() != BreakIterator.DONE) {
- count++;
- }
+ while (it.next() != BreakIterator.DONE) count++;
return count;
}
- /**
- * Count the number of times a pattern matches in a given string.
- *
- * @param value
- * The string to count occurances in.
+ /** Count the number of times a pattern matches in a given string.
*
- * @param pattern
- * The pattern to count occurances of.
+ * @param value The string to count occurrences in.
+ * @param pattern The pattern to count occurrences of.
+ *
* @return The number of times the pattern matches.
*/
public static int countMatches(final String value, final String pattern) {
Matcher mat = Pattern.compile(pattern).matcher(value);
int num = 0;
- while (mat.find())
- num += 1;
+ while (mat.find()) num += 1;
return num;
}
- /**
- * Get a substring until a specified string.
+ /** Get a substring until a specified string.
*
- * @param strang
- * The string to substring.
- * @param vx
- * The place to substring until.
+ * @param strang The string to substring.
+ * @param until The place to substring until.
*
* @return The specified substring.
*/
- public static String substringTo(String strang, String vx) {
- return substringTo(strang, vx, true);
+ public static String substringTo(String strang, String until) {
+ return substringTo(strang, until, true);
}
/**
* Get a substring until a specified string.
*
- * @param strang
- * The string to substring.
- * @param vx
- * The place to substring until.
- * @param allowFail
- * Whether or not to allow failure.
+ * @param strang The string to substring.
+ * @param until The place to substring until.
+ * @param allowFail Whether or not to allow failure.
*
* @return The specified substring, or null if the specified place to substring
* to was not found, and we were not allowed to fail.
*/
- public static String substringTo(String strang, String vx, boolean allowFail) {
- int idx = strang.indexOf(vx);
+ public static String substringTo(String strang, String until, boolean allowFail) {
+ int idx = strang.indexOf(until);
if (idx == -1) {
- if (allowFail)
- return strang;
-
- return null;
- }
-
- return strang.substring(0, strang.indexOf(vx));
- }
-
- /**
- * Split a line into a series of space-separated arguments, including string
- * literals.
- *
- * @param com
- * The command to split from
- * @return The split arguments.
- */
- public static List<String> processArguments(String com) {
- List<String> strings = new ArrayList<>();
-
- BooleanToggle togg = new BooleanToggle();
-
- for (String strang : TokenUtils.removeDQuotedStrings(com)) {
- if (togg.get()) {
- strings.add(TokenUtils.descapeString(strang));
- } else {
- for (String strung : strang.split("\\s+")) {
- strings.add(strung);
- }
- }
+ if (allowFail) return strang;
+ else return null;
}
- return strings;
+ return strang.substring(0, strang.indexOf(until));
}
private static class LineIterator implements Iterator<String> {
@@ -306,16 +222,13 @@ public class StringUtils {
boolean doLoop = true;
do {
- if (!scn.hasNextLine())
- break;
+ if (!scn.hasNextLine()) break;
tmp = scn.nextLine().trim();
// Skip blank lines
- if (skipBlanks && tmp.equals(""))
- continue;
- if (processComments && tmp.startsWith(commentInd))
- continue;
+ if (skipBlanks && tmp.equals("")) continue;
+ if (processComments && tmp.startsWith(commentInd)) continue;
doLoop = tmp.endsWith("\\") && !tmp.endsWith("\\\\");
@@ -330,11 +243,9 @@ public class StringUtils {
}
}
- /**
- * Read a series of lines from an input source.
+ /** Read a series of lines from an input source.
*
- * @param scn
- * The source to read the lines from.
+ * @param scn The source to read the lines from.
*
* @return An iterator over the lines from the input source.
*/
@@ -345,17 +256,10 @@ public class StringUtils {
/**
* Read a series of lines from an input source.
*
- * @param scn
- * The source to read the lines from.
- *
- * @param processComments
- * Whether or not to skip comment lines.
- *
- * @param commentInd
- * Indicator for starting comment lines.
- *
- * @param skipBlanks
- * Whether or not to skip blank lines.
+ * @param scn The source to read the lines from.
+ * @param processComments Whether or not to skip comment lines.
+ * @param commentInd Indicator for starting comment lines.
+ * @param skipBlanks Whether or not to skip blank lines.
*
* @return An iterator over the lines from the input source.
*/
@@ -371,27 +275,23 @@ public class StringUtils {
return itr;
}
- /**
- * Check if a string contains any one of a specified number of things,
+ /** Check if a string contains any one of a specified number of things,
* respecting groups.
*
- * @param haystack
- * The string to look in.
- * @param needles
- * The strings to look for.
+ * @param haystack The string to look in.
+ * @param needles The strings to look for.
+ *
* @return Whether or not any of the strings were contained outside of groups.
*/
public static boolean levelContains(String haystack, String... needles) {
return LevelSplitter.def.levelContains(haystack, needles);
}
- /**
- * Split a string, respecting groups.
+ /** Split a string, respecting groups.
*
- * @param phrase
- * The string to split.
- * @param splits
- * The strings to split on.
+ * @param phrase The string to split.
+ * @param splits The strings to split on.
+ *
* @return A list of split strings. If keepDelims is true, it also includes the
* delimiters in between the split strings.
*/
@@ -399,15 +299,12 @@ public class StringUtils {
return LevelSplitter.def.levelSplit(phrase, false, splits);
}
- /**
- * Split a string, respecting groups.
+ /** Split a string, respecting groups.
*
- * @param phrase
- * The string to split.
- * @param keepDelims
- * Whether or not to include the delimiters in the results.
- * @param splits
- * The strings to split on.
+ * @param phrase The string to split.
+ * @param keepDelims Whether or not to include the delimiters in the results.
+ * @param splits The strings to split on.
+ *
* @return A list of split strings. If keepDelims is true, it also includes the
* delimiters in between the split strings.
*/
@@ -415,4 +312,4 @@ public class StringUtils {
String... splits) {
return LevelSplitter.def.levelSplit(phrase, keepDelims, splits);
}
-}
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/funcutils/TestUtils.java b/base/src/main/java/bjc/utils/funcutils/TestUtils.java
index 3aa20a2..bf38cbe 100644
--- a/base/src/main/java/bjc/utils/funcutils/TestUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/TestUtils.java
@@ -15,27 +15,22 @@ public class TestUtils {
/**
* Assert an iterator provides a particular sequence of values.
*
- * @param src
- * The iterator to pull values from.
- * @param vals
- * The values to expect from the iterator.
+ * @param <T> The type of the values.
+ * @param src The iterator to pull values from.
+ * @param vals The values to expect from the iterator.
*/
@SafeVarargs
public static <T> void assertIteratorEquals(Iterator<T> src, T... vals) {
- for (T val : vals) {
- assertEquals(val, src.next());
- }
+ for (T val : vals) assertEquals(val, src.next());
}
/**
* Assert an iterator provides a particular sequence of values.
*
- * @param src
- * The iterator to pull values from.
- * @param hasMore
- * The expected value of hasNext for the iterator.
- * @param vals
- * The values to expect from the iterator.
+ * @param <T> The type of the values.
+ * @param src The iterator to pull values from.
+ * @param hasMore The expected value of hasNext for the iterator.
+ * @param vals The values to expect from the iterator.
*/
@SafeVarargs
public static <T> void assertIteratorEquals(boolean hasMore, Iterator<T> src,
@@ -46,6 +41,8 @@ public class TestUtils {
* Even though it's awkward, the boolean has to come first. Otherwise, there are
* cases where the compiler will get confused as to what the right value for T
* is, and be unable to pick an overload.
+ *
+ * This is a case where named parameter would be rather useful.
*/
assertIteratorEquals(src, vals);
@@ -55,11 +52,9 @@ public class TestUtils {
/**
* Assert that a list has a given set of contents.
*
- * @param src
- * The list of actual elements.
- *
- * @param exps
- * The list of expected elements.
+ * @param <T> The type of the values.
+ * @param src The list of actual elements.
+ * @param exps The list of expected elements.
*/
@SafeVarargs
public static <T> void assertListEquals(List<T> src, T... exps) {
diff --git a/base/src/main/java/bjc/utils/funcutils/TreeUtils.java b/base/src/main/java/bjc/utils/funcutils/TreeUtils.java
index d525773..5a1d9c8 100644
--- a/base/src/main/java/bjc/utils/funcutils/TreeUtils.java
+++ b/base/src/main/java/bjc/utils/funcutils/TreeUtils.java
@@ -1,11 +1,10 @@
package bjc.utils.funcutils;
import java.util.LinkedList;
-import java.util.function.Predicate;
+import java.util.function.*;
-import bjc.data.ITree;
-import bjc.funcdata.FunctionalList;
-import bjc.funcdata.IList;
+import bjc.data.*;
+import bjc.funcdata.*;
/**
* Implements various utilities for trees.
@@ -16,14 +15,13 @@ public class TreeUtils {
/**
* Convert a tree into a list of outline nodes that match a certain path.
*
- * @param tre
- * The tree to outline.
- * @param leafMarker
- * The path to mark nodes with.
+ * @param <T> The type of the values.
+ * @param tre The tree to outline.
+ * @param leafMarker The path to mark nodes with.
* @return The list of marked paths.
*/
- public static <T> IList<IList<T>> outlineTree(ITree<T> tre, Predicate<T> leafMarker) {
- IList<IList<T>> paths = new FunctionalList<>();
+ public static <T> ListEx<ListEx<T>> outlineTree(Tree<T> tre, Predicate<T> leafMarker) {
+ ListEx<ListEx<T>> paths = new FunctionalList<>();
LinkedList<T> path = new LinkedList<>();
path.add(tre.getHead());
@@ -34,15 +32,13 @@ public class TreeUtils {
}
/* Find a path in a tree. */
- private static <T> void findPath(ITree<T> subtree, LinkedList<T> path,
- Predicate<T> leafMarker, IList<IList<T>> paths) {
+ private static <T> void findPath(Tree<T> subtree, LinkedList<T> path,
+ Predicate<T> leafMarker, ListEx<ListEx<T>> paths) {
if (subtree.getChildrenCount() == 0 && leafMarker.test(subtree.getHead())) {
/* We're at a matching leaf node. Add it. */
- IList<T> finalPath = new FunctionalList<>();
+ ListEx<T> finalPath = new FunctionalList<>();
- for (T ePath : path) {
- finalPath.add(ePath);
- }
+ for (T ePath : path) finalPath.add(ePath);
finalPath.add(subtree.getHead());
@@ -56,4 +52,43 @@ public class TreeUtils {
path.removeLast();
}
}
+
+ /**
+ * Performs 'variable substitution' or something along those lines on a tree.
+ *
+ * @param <ContainedType> The type of element contained in the tree.
+ * @param tree The tree to do expansion in.
+ * @param marker The function to mark which nodes should be expanded.
+ * @param expander The function to expand nodes.
+ * @return A transformed copy of the tree.
+ */
+ public static <ContainedType> Tree<ContainedType> substitute(
+ Tree<ContainedType> tree,
+ Predicate<ContainedType> marker,
+ Function<ContainedType, Tree<ContainedType>> expander) {
+ tree.topDownTransform((contents) -> {
+ if (marker.test(contents)) return TopDownTransformResult.TRANSFORM;
+ else return TopDownTransformResult.PASSTHROUGH;
+ }, (node) -> {
+ return expander.apply(node.getHead());
+ });
+ return tree;
+ }
+
+ /**
+ * Performs 'variable substitution' or something along those lines on a tree.
+ *
+ * @param <ContainedType> The type of element contained in the tree.
+ * @param tree The tree to do expansion in.
+ * @param environment A map which contains the variables to substitute.
+ * @return A transformed copy of the tree.
+ */
+ public static <ContainedType> Tree<ContainedType> substitute(
+ Tree<ContainedType> tree,
+ MapEx<ContainedType, Tree<ContainedType>> environment) {
+ return substitute(
+ tree,
+ environment::containsKey,
+ (element) -> environment.get(element).get());
+ }
}