diff options
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/data/experimental')
6 files changed, 548 insertions, 55 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 index 2767897..7d1d7a0 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java @@ -15,8 +15,11 @@ import java.util.function.UnaryOperator; 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 + * + * @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( @@ -82,4 +85,15 @@ public interface IHolder<ContainedType> { */ public <UnwrappedType> UnwrappedType unwrap( Function<ContainedType, UnwrappedType> unwrapper); + + /** + * Replace the held value with a new one + * + * @param newValue + * The value to hold instead + * @return The holder itself + */ + public default IHolder<ContainedType> replace(ContainedType newValue) { + return transform((oldValue) -> newValue); + } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java new file mode 100644 index 0000000..fb9648e --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java @@ -0,0 +1,84 @@ +package bjc.utils.data.experimental; + +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Represents a pair of values + * + * @author ben + * @param <LeftType> + * The type of the left side of the pair + * @param <RightType> + * The type of the right side of the pair + * + */ +public interface IPair<LeftType, RightType> { + /** + * Bind a function to the left value in this pair + * + * @param <BoundLeft> + * The type of the bound value + * @param leftBinder + * The function to use to bind + * @return A pair with the left type bound + */ + public <BoundLeft> IPair<BoundLeft, RightType> bindLeft( + Function<LeftType, IPair<BoundLeft, RightType>> leftBinder); + + /** + * Bind a function to the right value in this pair + * + * @param <BoundRight> + * The type of the bound value + * @param rightBinder + * The function to use to bind + * @return A pair with the right type bound + */ + public <BoundRight> IPair<LeftType, BoundRight> bindRight( + Function<RightType, IPair<LeftType, BoundRight>> rightBinder); + + /** + * Bind a function across the values in this pair + * + * @param <BoundLeft> + * The type of the bound left + * @param <BoundRight> + * The type of the bound right + * @param binder + * The function to bind with + * @return The bound pair + */ + public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( + BiFunction<LeftType, RightType, IPair<BoundLeft, BoundRight>> binder); + + /** + * Merge the two values in this pair into a single value + * + * @param <MergedType> + * The type of the single value + * @param merger + * The function to use for merging + * @return The pair, merged into a single value + */ + public <MergedType> MergedType merge( + BiFunction<LeftType, RightType, MergedType> merger); + + /** + * Get the value on the left side of the pair + * + * @return The value on the left side of the pair + */ + public default LeftType getLeft() { + return merge((leftValue, rightValue) -> leftValue); + } + + /** + * Get the value on the right side of the pair + * + * @return The value on the right side of the pair + */ + public default RightType getRight() { + return merge((leftValue, rightValue) -> rightValue); + } +} 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 index 3cf0987..1780f2d 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java @@ -42,29 +42,32 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { return binder.apply(heldValue); } + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ @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); + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } else if (getClass() != obj.getClass()) { + return false; + } - return this; - } + Identity<?> other = (Identity<?>) obj; - @Override - public <UnwrappedType> UnwrappedType unwrap( - Function<ContainedType, UnwrappedType> unwrapper) { - return unwrapper.apply(heldValue); - } + if (heldValue == null) { + if (other.heldValue != null) { + return false; + } + } else if (!heldValue.equals(other.heldValue)) { + return false; + } - @Override - public String toString() { - return "holding[v=" + heldValue + "]"; + return true; } /* @@ -85,31 +88,28 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { 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; - } + public <MappedType> IHolder<MappedType> map( + Function<ContainedType, MappedType> mapper) { + return new Identity<>(mapper.apply(heldValue)); + } - Identity<?> other = (Identity<?>) obj; + @Override + public String toString() { + return "holding[v=" + heldValue + "]"; + } - if (heldValue == null) { - if (other.heldValue != null) { - return false; - } - } else if (!heldValue.equals(other.heldValue)) { - return false; - } + @Override + public IHolder<ContainedType> transform( + UnaryOperator<ContainedType> transformer) { + heldValue = transformer.apply(heldValue); - return true; + return this; + } + + @Override + public <UnwrappedType> UnwrappedType unwrap( + Function<ContainedType, UnwrappedType> unwrapper) { + return unwrapper.apply(heldValue); } }
\ 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 index e919fec..0d6fcef 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java @@ -26,8 +26,7 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { private boolean holderBound; - private IFunctionalList<UnaryOperator<BoundContainedType>> actions = - new FunctionalList<>(); + private IFunctionalList<UnaryOperator<BoundContainedType>> actions = new FunctionalList<>(); public BoundLazy(Supplier<IHolder<OldType>> supp, Function<OldType, IHolder<BoundContainedType>> binder) { @@ -38,8 +37,7 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { @Override public <BoundType> IHolder<BoundType> bind( Function<BoundContainedType, IHolder<BoundType>> bindr) { - IFunctionalList<UnaryOperator<BoundContainedType>> pendingActions = - new FunctionalList<>(); + IFunctionalList<UnaryOperator<BoundContainedType>> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); @@ -62,8 +60,7 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { @Override public <MappedType> IHolder<MappedType> map( Function<BoundContainedType, MappedType> mapper) { - IFunctionalList<UnaryOperator<BoundContainedType>> pendingActions = - new FunctionalList<>(); + IFunctionalList<UnaryOperator<BoundContainedType>> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); @@ -101,12 +98,19 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { return boundHolder.unwrap(unwrapper); } + @Override + public String toString() { + if (holderBound) { + return boundHolder.toString(); + } + + return "(unmaterialized)"; + } } private Supplier<ContainedType> valueSupplier; - private IFunctionalList<UnaryOperator<ContainedType>> actions = - new FunctionalList<>(); + private IFunctionalList<UnaryOperator<ContainedType>> actions = new FunctionalList<>(); private boolean valueMaterialized; @@ -146,8 +150,7 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { @Override public <BoundType> IHolder<BoundType> bind( Function<ContainedType, IHolder<BoundType>> binder) { - IFunctionalList<UnaryOperator<ContainedType>> pendingActions = - new FunctionalList<>(); + IFunctionalList<UnaryOperator<ContainedType>> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); @@ -167,8 +170,7 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { @Override public <MappedType> IHolder<MappedType> map( Function<ContainedType, MappedType> mapper) { - IFunctionalList<UnaryOperator<ContainedType>> pendingActions = - new FunctionalList<>(); + IFunctionalList<UnaryOperator<ContainedType>> pendingActions = new FunctionalList<>(); actions.forEach(pendingActions::add); @@ -210,4 +212,17 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { return unwrapper.apply(heldValue); } + + @Override + public String toString() { + if (valueMaterialized) { + if (actions.isEmpty()) { + return "value[v='" + heldValue + "']"; + } + + return "value[v='" + heldValue + "'] (has pending transforms)"; + } + + return "(unmaterialized)"; + } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java new file mode 100644 index 0000000..04a4b61 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java @@ -0,0 +1,317 @@ +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 <LeftType> + * The type on the left side of the pair + * @param <RightType> + * The type on the right side of the pair + */ +public class LazyPair<LeftType, RightType> + implements IPair<LeftType, RightType> { + private static class HalfBoundLazyPair<OldType, NewLeft, NewRight> + implements IPair<NewLeft, NewRight> { + private Supplier<OldType> oldSupplier; + + private Function<OldType, IPair<NewLeft, NewRight>> binder; + + private IPair<NewLeft, NewRight> boundPair; + private boolean pairBound; + + public HalfBoundLazyPair(Supplier<OldType> oldSupp, + Function<OldType, IPair<NewLeft, NewRight>> bindr) { + oldSupplier = oldSupp; + binder = bindr; + } + + @Override + public <BoundLeft> IPair<BoundLeft, NewRight> bindLeft( + Function<NewLeft, IPair<BoundLeft, NewRight>> leftBinder) { + Supplier<NewLeft> leftSupp = () -> { + IPair<NewLeft, NewRight> newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(oldSupplier.get()); + } + + return newPair.getLeft(); + }; + + return new HalfBoundLazyPair<>(leftSupp, leftBinder); + } + + @Override + public <BoundRight> IPair<NewLeft, BoundRight> bindRight( + Function<NewRight, IPair<NewLeft, BoundRight>> rightBinder) { + Supplier<NewRight> rightSupp = () -> { + IPair<NewLeft, NewRight> newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(oldSupplier.get()); + } + + return newPair.getRight(); + }; + + return new HalfBoundLazyPair<>(rightSupp, rightBinder); + } + + @Override + public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( + BiFunction<NewLeft, NewRight, IPair<BoundLeft, BoundRight>> bindr) { + IHolder<IPair<NewLeft, NewRight>> newPair = new Identity<>( + boundPair); + IHolder<Boolean> newPairMade = new Identity<>(pairBound); + + Supplier<NewLeft> leftSupp = () -> { + if (!newPairMade.getValue()) { + newPair.replace(binder.apply(oldSupplier.get())); + newPairMade.replace(true); + } + + return newPair.unwrap((pair) -> pair.getLeft()); + }; + + Supplier<NewRight> 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> MergedType merge( + BiFunction<NewLeft, NewRight, MergedType> merger) { + if (!pairBound) { + boundPair = binder.apply(oldSupplier.get()); + + pairBound = true; + } + + return boundPair.merge(merger); + } + } + + private static class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> + implements IPair<NewLeft, NewRight> { + private Supplier<OldLeft> leftSupplier; + private Supplier<OldRight> rightSupplier; + + private BiFunction<OldLeft, OldRight, IPair<NewLeft, NewRight>> binder; + + private IPair<NewLeft, NewRight> boundPair; + + private boolean pairBound; + + public BoundLazyPair(Supplier<OldLeft> leftSupp, + Supplier<OldRight> rightSupp, + BiFunction<OldLeft, OldRight, IPair<NewLeft, NewRight>> bindr) { + leftSupplier = leftSupp; + rightSupplier = rightSupp; + binder = bindr; + } + + @Override + public <BoundLeft> IPair<BoundLeft, NewRight> bindLeft( + Function<NewLeft, IPair<BoundLeft, NewRight>> leftBinder) { + Supplier<NewLeft> leftSupp = () -> { + IPair<NewLeft, NewRight> newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(leftSupplier.get(), + rightSupplier.get()); + } + + return newPair.getLeft(); + }; + + return new HalfBoundLazyPair<>(leftSupp, leftBinder); + } + + @Override + public <BoundRight> IPair<NewLeft, BoundRight> bindRight( + Function<NewRight, IPair<NewLeft, BoundRight>> rightBinder) { + Supplier<NewRight> rightSupp = () -> { + IPair<NewLeft, NewRight> newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(leftSupplier.get(), + rightSupplier.get()); + } + + return newPair.getRight(); + }; + + return new HalfBoundLazyPair<>(rightSupp, rightBinder); + } + + @Override + public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( + BiFunction<NewLeft, NewRight, IPair<BoundLeft, BoundRight>> bindr) { + IHolder<IPair<NewLeft, NewRight>> newPair = new Identity<>( + boundPair); + IHolder<Boolean> 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> MergedType merge( + BiFunction<NewLeft, NewRight, MergedType> merger) { + if (!pairBound) { + boundPair = binder.apply(leftSupplier.get(), + rightSupplier.get()); + + pairBound = true; + } + + return boundPair.merge(merger); + } + } + + private LeftType leftValue; + private RightType rightValue; + + private Supplier<LeftType> leftSupplier; + private Supplier<RightType> 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<LeftType> leftSupp, + Supplier<RightType> rightSupp) { + leftSupplier = leftSupp; + rightSupplier = rightSupp; + + leftMaterialized = false; + rightMaterialized = false; + } + + @Override + public <BoundLeft> IPair<BoundLeft, RightType> bindLeft( + Function<LeftType, IPair<BoundLeft, RightType>> leftBinder) { + Supplier<LeftType> leftSupp = () -> { + if (leftMaterialized) { + return leftValue; + } + + return leftSupplier.get(); + }; + + return new HalfBoundLazyPair<>(leftSupp, leftBinder); + } + + @Override + public <BoundRight> IPair<LeftType, BoundRight> bindRight( + Function<RightType, IPair<LeftType, BoundRight>> rightBinder) { + Supplier<RightType> rightSupp = () -> { + if (rightMaterialized) { + return rightValue; + } + + return rightSupplier.get(); + }; + + return new HalfBoundLazyPair<>(rightSupp, rightBinder); + } + + @Override + public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( + BiFunction<LeftType, RightType, IPair<BoundLeft, BoundRight>> binder) { + return new BoundLazyPair<>(leftSupplier, rightSupplier, binder); + } + + @Override + public <MergedType> MergedType merge( + BiFunction<LeftType, RightType, MergedType> 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; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java new file mode 100644 index 0000000..87378d7 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java @@ -0,0 +1,63 @@ +package bjc.utils.data.experimental; + +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * A pair of values, with nothing special about them. + * + * @author ben + * + * @param <LeftType> + * The type of the left value + * @param <RightType> + * The type of the right value + */ +public class Pair<LeftType, RightType> + implements IPair<LeftType, RightType> { + private LeftType leftValue; + private RightType rightValue; + + /** + * Create a new pair with both sides set to null + */ + public Pair() { + } + + /** + * Create a new pair with both sides set to the specified values + * + * @param left + * The value of the left side + * @param right + * The value of the right side + */ + public Pair(LeftType left, RightType right) { + leftValue = left; + rightValue = right; + } + + @Override + public <BoundLeft> IPair<BoundLeft, RightType> bindLeft( + Function<LeftType, IPair<BoundLeft, RightType>> leftBinder) { + return leftBinder.apply(leftValue); + } + + @Override + public <BoundRight> IPair<LeftType, BoundRight> bindRight( + Function<RightType, IPair<LeftType, BoundRight>> rightBinder) { + return rightBinder.apply(rightValue); + } + + @Override + public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( + BiFunction<LeftType, RightType, IPair<BoundLeft, BoundRight>> binder) { + return binder.apply(leftValue, rightValue); + } + + @Override + public <MergedType> MergedType merge( + BiFunction<LeftType, RightType, MergedType> merger) { + return merger.apply(leftValue, rightValue); + } +}
\ No newline at end of file |
