summaryrefslogtreecommitdiff
path: root/src/main/java/au/id/zancanaro/javacheck/RoseTree.java
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@zancanaro.id.au>2015-06-01 11:41:16 +1000
committerCarlo Zancanaro <carlo@zancanaro.id.au>2015-06-01 11:41:16 +1000
commit8187f024bae57267af514c5dcb730de09e573e41 (patch)
treecba17e2e770de4972f57b60cdd443248fd68c458 /src/main/java/au/id/zancanaro/javacheck/RoseTree.java
parentedfce37bc21699042baf14ad6d172d3187fe530c (diff)
Move packages, make lists shrink in size, generate lists instead of arrays as the 'primitive' operation (issues with generics)
Diffstat (limited to 'src/main/java/au/id/zancanaro/javacheck/RoseTree.java')
-rw-r--r--src/main/java/au/id/zancanaro/javacheck/RoseTree.java105
1 files changed, 105 insertions, 0 deletions
diff --git a/src/main/java/au/id/zancanaro/javacheck/RoseTree.java b/src/main/java/au/id/zancanaro/javacheck/RoseTree.java
new file mode 100644
index 0000000..d9fb508
--- /dev/null
+++ b/src/main/java/au/id/zancanaro/javacheck/RoseTree.java
@@ -0,0 +1,105 @@
+package au.id.zancanaro.javacheck;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+public class RoseTree<T> {
+ private final T value;
+ private final Iterable<RoseTree<T>> children;
+
+ public RoseTree(T value, Iterable<RoseTree<T>> children) {
+ this.value = value;
+ this.children = children;
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+ public Iterator<RoseTree<T>> getChildren() {
+ return children.iterator();
+ }
+
+ public static <T> RoseTree<T> pure(T value) {
+ return new RoseTree<>(value, Collections.emptyList());
+ }
+
+ public static <T> RoseTree<T> join(RoseTree<RoseTree<T>> tree) {
+ return new RoseTree<>(
+ tree.getValue().getValue(),
+ () -> Iterators.concat(
+ Iterators.mappingIterator(RoseTree::join, tree.children.iterator()),
+ tree.getValue().children.iterator()));
+ }
+
+ public static <T> Iterator<RoseTree<T>[]> permutations(RoseTree<T>[] trees) {
+ return Iterators.flatten(Iterators.rangeIterator(trees.length, index ->
+ Iterators.mappingIterator(child -> {
+ @SuppressWarnings("unchecked")
+ RoseTree<T>[] result = (RoseTree<T>[]) new RoseTree[trees.length];
+ for (int i = 0; i < trees.length; ++i) {
+ result[i] = (i == index ? child : trees[i]);
+ }
+ return result;
+ }, trees[index].getChildren())
+ ));
+ }
+
+ public static <T, R> RoseTree<R> zip(Function<List<T>, R> fn, RoseTree<T>[] trees) {
+ @SuppressWarnings("unchecked")
+ List<T> heads = new ArrayList(trees.length);
+ for (int i = 0; i < trees.length; ++i) {
+ heads.add(trees[i].getValue());
+ }
+ return new RoseTree<>(
+ fn.apply(heads),
+ () -> Iterators.mappingIterator(
+ roses -> RoseTree.zip(fn, roses),
+ RoseTree.permutations(trees)));
+ }
+
+ public <R> RoseTree<R> fmap(Function<T, R> f) {
+ return new RoseTree<>(
+ f.apply(this.value),
+ () -> Iterators.mappingIterator(tree -> tree.fmap(f), this.children.iterator()));
+ }
+
+ public <R> RoseTree<R> flatmap(Function<T, RoseTree<R>> f) {
+ return RoseTree.join(this.fmap(f));
+ }
+
+ public RoseTree<T> filter(Predicate<T> predicate) {
+ if (predicate.test(this.getValue())) {
+ return new RoseTree<>(
+ this.getValue(),
+ () -> Iterators.mappingIterator(tree -> tree.filter(predicate),
+ Iterators.filteringIterator(
+ tree -> predicate.test(tree.getValue()),
+ this.getChildren())));
+ } else {
+ throw new IllegalArgumentException("Current value doesn't match predicate: whoops!");
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public void print(Writer output) throws IOException {
+ print(output, Object::toString);
+ }
+
+ @SuppressWarnings("unused")
+ public void print(Writer output, Function<T, String> toString) throws IOException {
+ output.write(toString.apply(this.getValue()));
+ output.write('[');
+ for (RoseTree<T> child : children) {
+ child.print(output, toString);
+ }
+ output.write(']');
+ output.flush();
+ }
+}