From 843329de434bb334d90927c4d22345373a388530 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Tue, 2 Jul 2019 18:05:22 -0400 Subject: Rename package root The package root is now bjc, not io.github.bculkin2442. --- src/main/java/bjc/data/Lazy.java | 201 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 src/main/java/bjc/data/Lazy.java (limited to 'src/main/java/bjc/data/Lazy.java') diff --git a/src/main/java/bjc/data/Lazy.java b/src/main/java/bjc/data/Lazy.java new file mode 100644 index 0000000..0702665 --- /dev/null +++ b/src/main/java/bjc/data/Lazy.java @@ -0,0 +1,201 @@ +package bjc.data; + +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import bjc.data.internals.BoundLazy; +import bjc.funcdata.FunctionalList; +import bjc.funcdata.IList; + +/** + * A holder that holds a means to create a value, but doesn't actually compute + * the value until it's needed. + * + * @author ben + * + * @param + * The type of the value being held. + */ +public class Lazy implements IHolder { + /* The supplier of the type. */ + private Supplier valueSupplier; + /* The actual type value. */ + private ContainedType heldValue; + /* Whether the value has been created. */ + private boolean valueMaterialized; + + /* The list of pending actions on the value. */ + private IList> actions = new FunctionalList<>(); + + /** + * Create a new lazy value from the specified seed value. + * + * @param value + * The seed value to use. + */ + public Lazy(final ContainedType value) { + heldValue = value; + + valueMaterialized = true; + } + + /** + * Create a new lazy value from the specified value source. + * + * @param supp + * The source of a value to use. + */ + public Lazy(final Supplier supp) { + valueSupplier = new SingleSupplier<>(supp); + + valueMaterialized = false; + } + + /* Create a new value from a supplier and a list of actions. */ + private Lazy(final Supplier supp, final IList> pendingActions) { + valueSupplier = supp; + + actions = pendingActions; + } + + @Override + public IHolder bind(final Function> binder) { + final IList> pendingActions = new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + final Supplier supplier = () -> { + if(valueMaterialized) return heldValue; + + return valueSupplier.get(); + }; + + return new BoundLazy<>(() -> { + return new Lazy<>(supplier, pendingActions); + }, binder); + } + + @Override + public Function> lift(final Function func) { + return val -> { + return new Lazy<>(func.apply(val)); + }; + } + + @Override + public IHolder map(final Function mapper) { + final IList> pendingActions = new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + return new Lazy<>(() -> { + ContainedType currVal = heldValue; + + if(!valueMaterialized) { + currVal = valueSupplier.get(); + } + + return pendingActions.reduceAux(currVal, UnaryOperator::apply, + value -> mapper.apply(value)); + }); + } + + @Override + public String toString() { + if(valueMaterialized) { + if(actions.isEmpty()) { + return String.format("value[v='%s']", heldValue); + } + + return String.format("value[v='%s'] (has pending transforms)", heldValue); + } + + return "(unmaterialized)"; + } + + @Override + public IHolder transform(final UnaryOperator transformer) { + actions.add(transformer); + + return this; + } + + @Override + public UnwrappedType unwrap(final Function unwrapper) { + if(!valueMaterialized) { + heldValue = valueSupplier.get(); + + valueMaterialized = true; + } + + actions.forEach(action -> { + heldValue = action.apply(heldValue); + }); + + actions = new FunctionalList<>(); + + return unwrapper.apply(heldValue); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + (actions == null ? 0 : actions.hashCode()); + result = prime * result + (heldValue == null ? 0 : heldValue.hashCode()); + result = prime * result + (valueMaterialized ? 1231 : 1237); + + return result; + } + + @Override + public boolean equals(final Object obj) { + if(this == obj) return true; + if(obj == null) return false; + if(!(obj instanceof Lazy)) return false; + + final Lazy other = (Lazy) obj; + + if(valueMaterialized != other.valueMaterialized) return false; + + if(valueMaterialized) { + if(heldValue == null) { + if(other.heldValue != null) return false; + } else if(!heldValue.equals(other.heldValue)) return false; + } else + return false; + + if(actions == null) { + if(other.actions != null) return false; + } else if(actions.getSize() > 0 || other.actions.getSize() > 0) return false; + + return true; + } + + /** + * Create a new lazy container with an already present value. + * + * @param val + * The value for the lazy container. + * + * @return A new lazy container holding that value. + */ + public static Lazy lazy(final ContainedType val) { + return new Lazy<>(val); + } + + /** + * Create a new lazy container with a suspended value. + * + * @param supp + * The suspended value for the lazy container. + * + * @return A new lazy container that will un-suspend the value when + * necessary. + */ + public static Lazy lazy(final Supplier supp) { + return new Lazy<>(supp); + } +} -- cgit v1.2.3