package bjc.utils.data.lazy; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import bjc.utils.data.IHolder; import bjc.utils.funcdata.FunctionalList; /** * Holds a single value of a specific type. This is used for indirect * references to data, and more specifically for accessing non-final * variables from a lambda. AKA the identity monad * * This is a lazy variant of {@link IHolder} * * @author ben * * @param * The type of the data being held */ public class LazyHolder implements IHolder { /** * List of queued actions to be performed on realized values */ private FunctionalList> actions; /** * The value internally held by this lazy holder */ private T held; /** * The source for a value held by this lazy holder */ private Supplier heldSrc; /** * Create a new lazy holder with the given supplier * * @param src * The supplier for a value when it is neededs */ public LazyHolder(Supplier src) { heldSrc = src; held = null; } /** * Create a new lazy holder with the given value * * @param val * The value held in the holder */ public LazyHolder(T val) { held = val; } @Override public void doWith(Consumer f) { transform((val) -> { f.accept(val); return val; }); } @Override public IHolder map(Function f) { return new LazyHolder<>(() -> { if (held == null) { return actions.reduceAux(heldSrc.get(), Function::apply, f::apply); } else { return actions.reduceAux(held, Function::apply, f::apply); } }); } @Override public IHolder transform(Function f) { actions.add(f); return this; } @Override public E unwrap(Function f) { // Actualize ourselves if (held == null) { held = heldSrc.get(); } actions.forEach((act) -> held = act.apply(held)); return f.apply(held); } }