summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazy.java
blob: 9ab3c053ac33217bd031e079e94c102942314a2c (plain)
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
package bjc.utils.data;

import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IFunctionalList;

class BoundLazy<OldType, BoundContainedType>
		implements IHolder<BoundContainedType> {
	private Supplier<IHolder<OldType>>							oldSupplier;

	private Function<OldType, IHolder<BoundContainedType>>		binder;

	private IHolder<BoundContainedType>							boundHolder;

	private boolean												holderBound;

	private IFunctionalList<UnaryOperator<BoundContainedType>>	actions	= new FunctionalList<>();

	public BoundLazy(Supplier<IHolder<OldType>> supp,
			Function<OldType, IHolder<BoundContainedType>> binder) {
		oldSupplier = supp;
		this.binder = binder;
	}

	@Override
	public <BoundType> IHolder<BoundType> bind(
			Function<BoundContainedType, IHolder<BoundType>> bindr) {
		IFunctionalList<UnaryOperator<BoundContainedType>> pendingActions = new FunctionalList<>();

		actions.forEach(pendingActions::add);

		Supplier<IHolder<BoundContainedType>> typeSupplier = () -> {
			IHolder<BoundContainedType> oldHolder = boundHolder;

			if (!holderBound) {
				oldHolder = oldSupplier.get().unwrap(binder);
			}

			return pendingActions.reduceAux(oldHolder, (action, state) -> {
				return state.transform(action);
			}, (value) -> value);
		};

		return new BoundLazy<>(typeSupplier, bindr);
	}

	@Override
	public <MappedType> IHolder<MappedType> map(
			Function<BoundContainedType, MappedType> mapper) {
		IFunctionalList<UnaryOperator<BoundContainedType>> pendingActions = new FunctionalList<>();

		actions.forEach(pendingActions::add);

		Supplier<MappedType> typeSupplier = () -> {
			IHolder<BoundContainedType> oldHolder = boundHolder;

			if (!holderBound) {
				oldHolder = oldSupplier.get().unwrap(binder);
			}

			return pendingActions.reduceAux(oldHolder.getValue(),
					(action, state) -> {
						return action.apply(state);
					}, (value) -> mapper.apply(value));
		};

		return new Lazy<>(typeSupplier);
	}

	@Override
	public String toString() {
		if (holderBound) {
			return boundHolder.toString();
		}

		return "(unmaterialized)";
	}

	@Override
	public IHolder<BoundContainedType> transform(
			UnaryOperator<BoundContainedType> transformer) {
		actions.add(transformer);

		return this;
	}

	@Override
	public <UnwrappedType> UnwrappedType unwrap(
			Function<BoundContainedType, UnwrappedType> unwrapper) {
		if (!holderBound) {
			boundHolder = oldSupplier.get().unwrap(binder::apply);
		}

		return boundHolder.unwrap(unwrapper);
	}

	@Override
	public <NewType> Function<BoundContainedType, IHolder<NewType>> lift(
			Function<BoundContainedType, NewType> func) {
		return (val) -> {
			return new Lazy<>(func.apply(val));
		};
	}
}