diff options
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/data')
4 files changed, 420 insertions, 0 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java new file mode 100644 index 0000000..2767897 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java @@ -0,0 +1,85 @@ +package bjc.utils.data.experimental; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.UnaryOperator; + +/** + * A holder of a single value. + * + * @author ben + * + * @param <ContainedType> + * The type of value held + */ +public interface IHolder<ContainedType> { + /** + * Bind a function across the value in this container + * @param <BoundType> The type of value in this container + * @param binder The function to bind to the value + * @return A holder from binding the value + */ + public <BoundType> IHolder<BoundType> bind( + Function<ContainedType, IHolder<BoundType>> binder); + + /** + * Apply an action to the value + * + * @param action + * The action to apply to the value + */ + public default void doWith(Consumer<ContainedType> action) { + transform((value) -> { + action.accept(value); + + return value; + }); + } + + /** + * Get the value contained in this holder without changing it. + * + * @return The value held in this holder + */ + public default ContainedType getValue() { + return unwrap((value) -> value); + } + + /** + * Create a new holder with a mapped version of the value in this + * holder. + * + * Does not change the internal state of this holder + * + * @param <MappedType> + * The type of the mapped value + * @param mapper + * The function to do mapping with + * @return A holder with the mapped value + */ + public <MappedType> IHolder<MappedType> map( + Function<ContainedType, MappedType> mapper); + + /** + * Transform the value held in this holder + * + * @param transformer + * The function to transform the value with + * @return The holder itself, for easy chaining + */ + public IHolder<ContainedType> transform( + UnaryOperator<ContainedType> transformer); + + /** + * Unwrap the value contained in this holder so that it is no longer + * held + * + * @param <UnwrappedType> + * The type of the unwrapped value + * @param unwrapper + * The function to use to unwrap the value + * @return The unwrapped held value + */ + public <UnwrappedType> UnwrappedType unwrap( + Function<ContainedType, UnwrappedType> unwrapper); +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java new file mode 100644 index 0000000..3cf0987 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java @@ -0,0 +1,115 @@ +package bjc.utils.data.experimental; + +import java.util.function.Function; +import java.util.function.UnaryOperator; + +/** + * @author ben + * + * @param <ContainedType> + */ +/** + * Simple implementation of IHolder that has no hidden behavior + * + * @author ben + * + * @param <ContainedType> + * The type contained in the holder + */ +public class Identity<ContainedType> implements IHolder<ContainedType> { + private ContainedType heldValue; + + /** + * Create a holder holding null + */ + public Identity() { + heldValue = null; + } + + /** + * Create a holder holding the specified value + * + * @param value + * The value to hold + */ + public Identity(ContainedType value) { + heldValue = value; + } + + @Override + public <BoundType> IHolder<BoundType> bind( + Function<ContainedType, IHolder<BoundType>> binder) { + return binder.apply(heldValue); + } + + @Override + public <MappedType> IHolder<MappedType> map( + Function<ContainedType, MappedType> mapper) { + return new Identity<>(mapper.apply(heldValue)); + } + + @Override + public IHolder<ContainedType> transform( + UnaryOperator<ContainedType> transformer) { + heldValue = transformer.apply(heldValue); + + return this; + } + + @Override + public <UnwrappedType> UnwrappedType unwrap( + Function<ContainedType, UnwrappedType> unwrapper) { + return unwrapper.apply(heldValue); + } + + @Override + public String toString() { + return "holding[v=" + heldValue + "]"; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + + int result = 1; + + int fieldHash = (heldValue == null) ? 0 : heldValue.hashCode(); + + result = prime * result + fieldHash; + + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } else if (getClass() != obj.getClass()) { + return false; + } + + Identity<?> other = (Identity<?>) obj; + + if (heldValue == null) { + if (other.heldValue != null) { + return false; + } + } else if (!heldValue.equals(other.heldValue)) { + return false; + } + + return true; + } +}
\ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java new file mode 100644 index 0000000..e919fec --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java @@ -0,0 +1,213 @@ +package bjc.utils.data.experimental; + +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; + +/** + * A holder that holds a means to create a value, but doesn't actually + * compute the value until it's needed + * + * @author ben + * + * @param <ContainedType> + */ +public class Lazy<ContainedType> implements IHolder<ContainedType> { + private static 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 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); + } + + } + + private Supplier<ContainedType> valueSupplier; + + private IFunctionalList<UnaryOperator<ContainedType>> actions = + new FunctionalList<>(); + + private boolean valueMaterialized; + + private ContainedType heldValue; + + /** + * Create a new lazy value from the specified seed value + * + * @param value + * The seed value to use + */ + public Lazy(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(Supplier<ContainedType> supp) { + valueSupplier = supp; + + valueMaterialized = false; + } + + private Lazy(Supplier<ContainedType> supp, + IFunctionalList<UnaryOperator<ContainedType>> pendingActions) { + valueSupplier = supp; + + actions = pendingActions; + } + + @Override + public <BoundType> IHolder<BoundType> bind( + Function<ContainedType, IHolder<BoundType>> binder) { + IFunctionalList<UnaryOperator<ContainedType>> pendingActions = + new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + Supplier<ContainedType> supplier = () -> { + if (valueMaterialized) { + return heldValue; + } + + return valueSupplier.get(); + }; + + return new BoundLazy<>(() -> { + return new Lazy<>(supplier, pendingActions); + }, binder); + } + + @Override + public <MappedType> IHolder<MappedType> map( + Function<ContainedType, MappedType> mapper) { + IFunctionalList<UnaryOperator<ContainedType>> pendingActions = + new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + return new Lazy<>(() -> { + ContainedType currVal = heldValue; + + if (!valueMaterialized) { + currVal = valueSupplier.get(); + } + + return pendingActions.reduceAux(currVal, + UnaryOperator<ContainedType>::apply, + (value) -> mapper.apply(value)); + }); + } + + @Override + public IHolder<ContainedType> transform( + UnaryOperator<ContainedType> transformer) { + actions.add(transformer); + + return this; + } + + @Override + public <UnwrappedType> UnwrappedType unwrap( + Function<ContainedType, UnwrappedType> unwrapper) { + if (!valueMaterialized) { + heldValue = valueSupplier.get(); + + valueMaterialized = true; + } + + actions.forEach((action) -> { + heldValue = action.apply(heldValue); + }); + + actions = new FunctionalList<>(); + + return unwrapper.apply(heldValue); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java new file mode 100644 index 0000000..72e1007 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java @@ -0,0 +1,7 @@ +/** + * Experimental redoing of data structures + * + * @author ben + * + */ +package bjc.utils.data.experimental;
\ No newline at end of file |
