package bjc.utils.data.lazy; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Supplier; import bjc.utils.data.GenHolder; import bjc.utils.data.IPair; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IFunctionalList; /** * New implementation of lazy pair not delegating to {@link LazyHolder} * * @author ben * @param * The type on the left side of the pair * @param * The type on the right side of the pair * */ public class NewLazyPair implements IPair, ILazy { private static class BoundLazyPair implements IPair { private Supplier oldLeftSupplier; private Supplier oldRightSupplier; private BiFunction> newPairSupplier; private IPair newPair; private boolean newPairMaterialized; public BoundLazyPair(Supplier leftSup, Supplier rightSup, BiFunction> binder) { oldLeftSupplier = leftSup; oldRightSupplier = rightSup; newPairSupplier = binder; } @Override public IPair bind( BiFunction> binder) { // TODO Auto-generated method stub return null; } @Override public void doWith(BiConsumer action) { // TODO Auto-generated method stub } @Override public E merge(BiFunction merger) { if (!newPairMaterialized) { newPair = newPairSupplier.apply(oldLeftSupplier.get(), oldRightSupplier.get()); } return newPair.merge(merger); } } private L leftValue; private R rightValue; private Supplier rightValueSupplier; private Supplier leftValueSupplier; private boolean rightMaterialized; private boolean leftMaterialized; private IFunctionalList> actions; /** * Create a new lazy pair * * @param leftVal * The left value in the pair * @param rightVal * The right value in the pair */ public NewLazyPair(L leftVal, R rightVal) { leftValueSupplier = () -> leftVal; rightValueSupplier = () -> rightVal; } /** * Create a new lazy pair * * @param leftSupplier * The supplier for the left value in the pair * @param rightSupplier * The supplier for the right value in the pair */ public NewLazyPair(Supplier leftSupplier, Supplier rightSupplier) { leftValueSupplier = leftSupplier; rightValueSupplier = rightSupplier; } @Override public void applyPendingActions() { if (!isMaterialized()) { throw new UnsupportedOperationException( "Can only apply actions to materialized values"); } actions.forEach((action) -> { action.accept(leftValue, rightValue); }); actions = new FunctionalList<>(); } private void applyPossiblyPendingActions(GenHolder hasActions, IFunctionalList> pendingActions) { if (hasActions.unwrap((val) -> val) == true) { pendingActions.forEach((action) -> { action.accept(leftValue, rightValue); }); hasActions.transform((val) -> false); } } @Override public IPair bind( BiFunction> binder) { GenHolder hasActions = new GenHolder<>(true); IFunctionalList> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); return new BoundLazyPair<>(() -> { applyPossiblyPendingActions(hasActions, pendingActions); return leftValue; }, () -> { applyPossiblyPendingActions(hasActions, pendingActions); return rightValue; }, binder); } @Override public void doWith(BiConsumer action) { actions.add(action); } @Override public boolean hasPendingActions() { return !actions.isEmpty(); } @Override public boolean isMaterialized() { if (leftValueSupplier == null) { if (rightValueSupplier == null) { return true; } return rightMaterialized; } if (rightValueSupplier == null) { return leftMaterialized; } return leftMaterialized && rightMaterialized; } @Override public void materialize() { if (isMaterialized()) { throw new UnsupportedOperationException( "Cannot materialize lazy object twice"); } if (leftValueSupplier != null) { leftValue = leftValueSupplier.get(); } if (rightValueSupplier != null) { rightValue = rightValueSupplier.get(); } } @Override public E merge(BiFunction merger) { if (!isMaterialized()) { materialize(); } applyPendingActions(); return merger.apply(leftValue, rightValue); } }