-
Notifications
You must be signed in to change notification settings - Fork 47
/
ListReduction.java
108 lines (90 loc) · 2.98 KB
/
ListReduction.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package org.reactfx.collection;
import java.util.function.BinaryOperator;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.control.IndexRange;
import org.reactfx.Subscription;
import org.reactfx.util.Experimental;
import org.reactfx.util.FingerTree;
import org.reactfx.util.ToSemigroup;
import org.reactfx.value.Val;
import org.reactfx.value.ValBase;
class ListReduction<T> extends ValBase<T> {
private final ObservableList<T> input;
private final BinaryOperator<T> reduction;
private final ToSemigroup<T, T> monoid;
private FingerTree<T, T> tree = null;
ListReduction(
ObservableList<T> input,
BinaryOperator<T> reduction) {
this.input = input;
this.reduction = reduction;
monoid = new ToSemigroup<T, T>() {
@Override
public T apply(T t) {
return t;
}
@Override
public T reduce(T left, T right) {
return reduction.apply(left, right);
}
};
}
@Override
protected Subscription connect() {
assert tree == null;
tree = FingerTree.mkTree(input, monoid);
return LiveList.observeChanges(input, ch -> {
for(ListModification<? extends T> mod: ch) {
FingerTree<T, T> left = tree.split(mod.getFrom())._1;
FingerTree<T, T> right = tree.split(mod.getFrom() + mod.getRemovedSize())._2;
FingerTree<T, T> middle = FingerTree.mkTree(mod.getAddedSubList(), monoid);
tree = left.join(middle).join(right);
}
invalidate();
})
.and(() -> tree = null);
}
protected int getFrom(int max) {
return 0;
}
protected int getTo(int max) {
return max;
}
@Override
protected final T computeValue() {
if(isObservingInputs()) {
assert tree != null;
int max = tree.getLeafCount();
return tree.getSummaryBetween(getFrom(max), getTo(max)).orElse(null);
} else {
assert tree == null;
int max = input.size();
return input.subList(getFrom(max), getTo(max))
.stream().reduce(reduction).orElse(null);
}
}
}
@Experimental
class ListRangeReduction<T> extends ListReduction<T> {
private final ObservableValue<IndexRange> range;
ListRangeReduction(
ObservableList<T> input,
ObservableValue<IndexRange> range,
BinaryOperator<T> reduction) {
super(input, reduction);
this.range = range;
}
@Override
protected Subscription connect() {
return super.connect().and(Val.observeInvalidations(range, obs -> invalidate()));
}
@Override
protected int getFrom(int max) {
return Math.min(range.getValue().getStart(), max);
}
@Override
protected int getTo(int max) {
return Math.min(range.getValue().getEnd(), max);
}
}