fj.data.fingertrees.Deep Maven / Gradle / Ivy
package fj.data.fingertrees;
import fj.*;
import fj.data.Option;
import fj.data.vector.V2;
import fj.data.vector.V3;
import fj.data.vector.V4;
import static fj.Function.constant;
import static fj.data.List.list;
import static fj.Function.flip;
/**
* A finger tree with 1-4-digits on the left and right, and a finger tree of 2-3-nodes in the middle.
*/
public final class Deep extends FingerTree {
private final V v;
private final Digit prefix;
private final FingerTree> middle;
private final Digit suffix;
Deep(final Measured m, final V v, final Digit prefix,
final FingerTree> middle,
final Digit suffix) {
super(m);
this.v = v;
this.prefix = prefix;
this.middle = middle;
this.suffix = suffix;
}
/**
* Returns the first few elements of this tree.
*
* @return the first few elements of this tree.
*/
public Digit prefix() {
return prefix;
}
/**
* Returns a finger tree of the inner nodes of this tree.
*
* @return a finger tree of the inner nodes of this tree.
*/
public FingerTree> middle() {
return middle;
}
/**
* Returns the last few elements of this tree.
*
* @return the last few elements of this tree.
*/
public Digit suffix() {
return suffix;
}
@Override public B foldRight(final F> aff, final B z) {
return prefix.foldRight(aff, middle.foldRight(flip(Node.foldRight_(aff)), suffix.foldRight(aff, z)));
}
@Override public A reduceRight(final F> aff) {
return prefix.foldRight(aff, middle.foldRight(flip(Node.foldRight_(aff)), suffix.reduceRight(aff)));
}
@Override public B foldLeft(final F> bff, final B z) {
return suffix.foldLeft(bff, middle.foldLeft(Node.foldLeft_(bff), prefix.foldLeft(bff, z)));
}
@Override public A reduceLeft(final F> aff) {
return suffix.foldLeft(aff, middle.foldLeft(Node.foldLeft_(aff), prefix.reduceLeft(aff)));
}
@Override public FingerTree map(final F abf, final Measured m) {
return new Deep(m, v, prefix.map(abf, m), middle.map(Node.liftM(abf, m), m.nodeMeasured()),
suffix.map(abf, m));
}
/**
* Returns the sum of the measurements of this tree's elements, according to the monoid.
*
* @return the sum of the measurements of this tree's elements, according to the monoid.
*/
public V measure() {
return v;
}
/**
* Pattern matching on the tree. Matches the function on the Deep tree.
*/
@Override public B match(final F, B> empty, final F, B> single,
final F, B> deep) {
return deep.f(this);
}
@Override public FingerTree cons(final A a) {
final Measured m = measured();
final V measure = m.sum(m.measure(a), v);
final MakeTree mk = mkTree(m);
return prefix.match(
one -> new Deep<>(m, measure, mk.two(a, one.value()), middle, suffix),
two -> new Deep<>(m, measure, mk.three(a, two.values()._1(), two.values()._2()), middle, suffix),
three -> new Deep<>(m, measure, mk.four(a, three.values()._1(), three.values()._2(), three.values()._3()), middle, suffix),
four -> new Deep<>(m, measure, mk.two(a, four.values()._1()), middle.cons(mk.node3(four.values()._2(), four.values()._3(), four.values()._4())), suffix));
}
public FingerTree snoc(final A a) {
final Measured m = measured();
final V measure = m.sum(m.measure(a), v);
final MakeTree mk = mkTree(m);
return suffix.match(
one -> new Deep<>(m, measure, prefix, middle, mk.two(one.value(), a)),
two -> new Deep<>(m, measure, prefix, middle, mk.three(two.values()._1(), two.values()._2(), a)),
three -> new Deep<>(m, measure, prefix, middle, mk.four(three.values()._1(), three.values()._2(), three.values()._3(), a)),
four -> new Deep<>(m, measure, prefix, middle.snoc(mk.node3(four.values()._1(), four.values()._2(), four.values()._3())), mk.two(four.values()._4(), a)));
}
@Override public A head() {
return prefix.match(
One::value,
two -> two.values()._1(),
three -> three.values()._1(),
four -> four.values()._1());
}
@Override public A last() {
return suffix.match(
One::value,
two -> two.values()._2(),
three -> three.values()._3(),
four -> four.values()._4());
}
private static final FingerTree deepL(final Measured measured, final Option> lOpt, final FingerTree> m, final Digit r) {
return lOpt.option(
P.lazy(() -> m.isEmpty() ? r.toTree() : mkTree(measured).deep(m.head().toDigit(), m.tail(), r)),
(F, FingerTree>) l -> mkTree(measured).deep(l, m, r)
);
}
private static final FingerTree deepR(final Measured measured, final Option> rOpt, final FingerTree> m, final Digit l) {
return rOpt.option(
P.lazy(() -> m.isEmpty() ? l.toTree() : mkTree(measured).deep(l, m.init(), m.last().toDigit())),
(F, FingerTree>) r -> mkTree(measured).deep(l, m, r)
);
}
@Override public FingerTree tail() { return deepL(measured(), prefix.tail(), middle, suffix); }
@Override public FingerTree init() { return deepR(measured(), suffix.init(), middle, prefix); }
@Override public FingerTree append(final FingerTree t) {
final Measured m = measured();
return t.match(
constant(this),
single -> snoc(single.value()),
deep -> new Deep<>(m, m.sum(measure(), deep.measure()), prefix,
addDigits0(m, middle, suffix, deep.prefix, deep.middle), deep.suffix));
}
@Override P3, A, FingerTree> split1(final F predicate, final V acc) {
final Measured m = measured();
final V accL = m.sum(acc, prefix.measure());
if (predicate.f(accL)) {
final P3