package bjc.utils.data.experimental; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; /** * A lazy implementation of a pair * * @author ben * * @param * The type on the left side of the pair * @param * The type on the right side of the pair */ public class LazyPair implements IPair { private static class HalfBoundLazyPair implements IPair { private Supplier oldSupplier; private Function> binder; private IPair boundPair; private boolean pairBound; public HalfBoundLazyPair(Supplier oldSupp, Function> bindr) { oldSupplier = oldSupp; binder = bindr; } @Override public IPair bindLeft( Function> leftBinder) { Supplier leftSupp = () -> { IPair newPair = boundPair; if (!pairBound) { newPair = binder.apply(oldSupplier.get()); } return newPair.getLeft(); }; return new HalfBoundLazyPair<>(leftSupp, leftBinder); } @Override public IPair bindRight( Function> rightBinder) { Supplier rightSupp = () -> { IPair newPair = boundPair; if (!pairBound) { newPair = binder.apply(oldSupplier.get()); } return newPair.getRight(); }; return new HalfBoundLazyPair<>(rightSupp, rightBinder); } @Override public IPair bind( BiFunction> bindr) { IHolder> newPair = new Identity<>( boundPair); IHolder newPairMade = new Identity<>(pairBound); Supplier leftSupp = () -> { if (!newPairMade.getValue()) { newPair.replace(binder.apply(oldSupplier.get())); newPairMade.replace(true); } return newPair.unwrap((pair) -> pair.getLeft()); }; Supplier rightSupp = () -> { if (!newPairMade.getValue()) { newPair.replace(binder.apply(oldSupplier.get())); newPairMade.replace(true); } return newPair.unwrap((pair) -> pair.getRight()); }; return new BoundLazyPair<>(leftSupp, rightSupp, bindr); } @Override public MergedType merge( BiFunction merger) { if (!pairBound) { boundPair = binder.apply(oldSupplier.get()); pairBound = true; } return boundPair.merge(merger); } } private static class BoundLazyPair implements IPair { private Supplier leftSupplier; private Supplier rightSupplier; private BiFunction> binder; private IPair boundPair; private boolean pairBound; public BoundLazyPair(Supplier leftSupp, Supplier rightSupp, BiFunction> bindr) { leftSupplier = leftSupp; rightSupplier = rightSupp; binder = bindr; } @Override public IPair bindLeft( Function> leftBinder) { Supplier leftSupp = () -> { IPair newPair = boundPair; if (!pairBound) { newPair = binder.apply(leftSupplier.get(), rightSupplier.get()); } return newPair.getLeft(); }; return new HalfBoundLazyPair<>(leftSupp, leftBinder); } @Override public IPair bindRight( Function> rightBinder) { Supplier rightSupp = () -> { IPair newPair = boundPair; if (!pairBound) { newPair = binder.apply(leftSupplier.get(), rightSupplier.get()); } return newPair.getRight(); }; return new HalfBoundLazyPair<>(rightSupp, rightBinder); } @Override public IPair bind( BiFunction> bindr) { IHolder> newPair = new Identity<>( boundPair); IHolder newPairMade = new Identity<>(pairBound); return new BoundLazyPair<>(() -> { if (!newPairMade.getValue()) { newPair.replace(binder.apply(leftSupplier.get(), rightSupplier.get())); newPairMade.replace(false); } return newPair.unwrap((pair) -> pair.getLeft()); }, () -> { if (!newPairMade.getValue()) { newPair.replace(binder.apply(leftSupplier.get(), rightSupplier.get())); newPairMade.replace(false); } return newPair.unwrap((pair) -> pair.getRight()); }, bindr); } @Override public MergedType merge( BiFunction merger) { if (!pairBound) { boundPair = binder.apply(leftSupplier.get(), rightSupplier.get()); pairBound = true; } return boundPair.merge(merger); } } private LeftType leftValue; private RightType rightValue; private Supplier leftSupplier; private Supplier rightSupplier; private boolean leftMaterialized; private boolean rightMaterialized; /** * Create a new lazy pair, using the set value s * * @param leftVal * The value for the left side of the pair * @param rightVal * The value for the right side of the pair */ public LazyPair(LeftType leftVal, RightType rightVal) { leftValue = leftVal; rightValue = rightVal; leftMaterialized = true; rightMaterialized = true; } /** * Create a new lazy pair from the given value sources * * @param leftSupp * The source for a value on the left side of the pair * @param rightSupp * The source for a value on the right side of the pair */ public LazyPair(Supplier leftSupp, Supplier rightSupp) { leftSupplier = leftSupp; rightSupplier = rightSupp; leftMaterialized = false; rightMaterialized = false; } @Override public IPair bindLeft( Function> leftBinder) { Supplier leftSupp = () -> { if (leftMaterialized) { return leftValue; } return leftSupplier.get(); }; return new HalfBoundLazyPair<>(leftSupp, leftBinder); } @Override public IPair bindRight( Function> rightBinder) { Supplier rightSupp = () -> { if (rightMaterialized) { return rightValue; } return rightSupplier.get(); }; return new HalfBoundLazyPair<>(rightSupp, rightBinder); } @Override public IPair bind( BiFunction> binder) { return new BoundLazyPair<>(leftSupplier, rightSupplier, binder); } @Override public MergedType merge( BiFunction merger) { if (!leftMaterialized) { leftValue = leftSupplier.get(); leftMaterialized = true; } if (!rightMaterialized) { rightValue = rightSupplier.get(); rightMaterialized = true; } return merger.apply(leftValue, rightValue); } @Override public LeftType getLeft() { if (!leftMaterialized) { leftValue = leftSupplier.get(); leftMaterialized = true; } return leftValue; } @Override public RightType getRight() { if (!rightMaterialized) { rightValue = rightSupplier.get(); rightMaterialized = true; } return rightValue; } }