diff options
Diffstat (limited to 'src/main/java/bjc/data')
33 files changed, 1923 insertions, 1505 deletions
diff --git a/src/main/java/bjc/data/ArrayIterator.java b/src/main/java/bjc/data/ArrayIterator.java index 6d11a1d..c5f68cc 100644 --- a/src/main/java/bjc/data/ArrayIterator.java +++ b/src/main/java/bjc/data/ArrayIterator.java @@ -34,8 +34,7 @@ public class ArrayIterator<T> implements Iterator<T> { @SuppressWarnings("unchecked") @Override public T next() { - if (idx >= arr.length) - return null; + if (idx >= arr.length) return null; return (T) (arr[idx++]); } diff --git a/src/main/java/bjc/data/BooleanToggle.java b/src/main/java/bjc/data/BooleanToggle.java index af083f5..e0286d4 100644 --- a/src/main/java/bjc/data/BooleanToggle.java +++ b/src/main/java/bjc/data/BooleanToggle.java @@ -59,23 +59,18 @@ public class BooleanToggle implements Toggle<Boolean> { @Override public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof BooleanToggle)) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof BooleanToggle)) return false; final BooleanToggle other = (BooleanToggle) obj; - if (val != other.val) - return false; - - return true; + if (val != other.val) return false; + else return true; } @Override public String toString() { - return String.format("BooleanToggle [val=%s]", val); + return String.format("%s", val); } } diff --git a/src/main/java/bjc/data/Context.java b/src/main/java/bjc/data/Context.java new file mode 100644 index 0000000..7efdc4d --- /dev/null +++ b/src/main/java/bjc/data/Context.java @@ -0,0 +1,62 @@ +package bjc.data; + +/** + * Represents a 'context' which is a hierarchical set of objects. + * @author Ben Culkin + * + */ +public interface Context { + /** + * Register an object with this context. + * + * @param name The name of the object. + * @param o The object to register. + */ + void register(String name, Object o); + + /** + * Get the parent of this context. + * + * @return The parent of this context. + */ + Context getParent(); + + /** + * Get an object from this context. + * + * @param name The name of the object. + * + * @return The object bound to that name. + */ + Object get(String name); + + /** + * Get an object which is an instance of the provided class or a subclass + * thereof. + * + * @param <T> The type of the object. + * + * @param contract The class of the object. + * + * @return An instance of the provided class. + */ + <T> T get(Class<T> contract); + + /** + * Get a named object which is an instance of the provided class or a subclass + * thereof. + * + * @param <T> The type of the object. + * + * @param name The name of the object + * @param contract The class of the object. + * + * @return An instance of the provided class, with the given name.. + */ + default <T> T get(String name, Class<T> contract) { + Object obj = get(name); + return obj == null + ? getParent().get(name, contract) + : contract.cast(obj); + }; +} diff --git a/src/main/java/bjc/data/Contexts.java b/src/main/java/bjc/data/Contexts.java new file mode 100644 index 0000000..b028ad1 --- /dev/null +++ b/src/main/java/bjc/data/Contexts.java @@ -0,0 +1,103 @@ +package bjc.data; + +import java.util.*; + +/** + * Utility methods for dealing with contexts. + * + * @author Ben Culkin + * + */ +public class Contexts { + /** + * The null context, which always throws an exception. + */ + public static final Context NULL = new NullContextImpl(); + + private Contexts() { + throw new UnsupportedOperationException(); + } + + /** + * Create a new context with no parent. + * + * @return A context with no parent. + */ + public static Context create() { + return new ContextImpl(NULL); + } + + /** + * Create a context with the specified parent. + * + * @param parent The parent of this context. + * + * @return A context with the given context as its parent. + */ + public static Context create(Context parent) { + return new ContextImpl(parent); + } + + private static class NullContextImpl implements Context { + @Override + public Context getParent() { + return this; + } + + @Override + public void register(String name, Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public Object get(String name) { + throw new NoSuchElementException(); + } + + @Override + public <T> T get(Class<T> contract) { + throw new NoSuchElementException(); + } + } + + private static class ContextImpl implements Context { + + private final Context parent; + + private final Map<String, Object> objects; + + public ContextImpl(Context parent) { + this.parent = parent; + this.objects = new HashMap<>(); + } + + @Override + public void register(String name, Object o) { + objects.put(name, o); + } + + @Override + public Object get(String name) { + if (objects.containsKey(name)) { + return objects.get(name); + } + return parent.get(name); + } + + @SuppressWarnings("unchecked") + @Override + public <T> T get(Class<T> contract) { + for (Object o : objects.values()) { + if (contract.isInstance(o)) { + return (T) o; + } + } + return parent.get(contract); + } + + @Override + public Context getParent() { + return parent; + } + } +} diff --git a/src/main/java/bjc/data/Either.java b/src/main/java/bjc/data/Either.java index 55518d8..75447f2 100644 --- a/src/main/java/bjc/data/Either.java +++ b/src/main/java/bjc/data/Either.java @@ -1,7 +1,7 @@ package bjc.data; -import java.util.function.BiFunction; -import java.util.function.Function; +import java.util.*; +import java.util.function.*; /** * Represents a pair where only one side has a value. @@ -15,7 +15,7 @@ import java.util.function.Function; * The type that could be on the right. * */ -public class Either<LeftType, RightType> implements IPair<LeftType, RightType> { +public class Either<LeftType, RightType> { /** * Create a new either with the left value occupied. * @@ -72,141 +72,138 @@ public class Either<LeftType, RightType> implements IPair<LeftType, RightType> { } } - @Override - public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( - final BiFunction<LeftType, RightType, IPair<BoundLeft, BoundRight>> binder) { - if (binder == null) - throw new NullPointerException("Binder must not be null"); - - return binder.apply(leftVal, rightVal); + /** + * Perform a mapping over this either. + * + * @param <NewLeft> The new left type. + * @param <NewRight> The new right type. + * + * @param leftFunc The function to apply if this is a left either. + * @param rightFunc The function to apply if this is a right either. + * + * @return A new either, containing a value transformed by the appropriate function. + */ + public <NewLeft, NewRight> Either<NewLeft, NewRight> map( + Function<LeftType, NewLeft> leftFunc, + Function<RightType, NewRight> rightFunc) + { + if (isLeft) return left(leftFunc.apply(leftVal)); + else return right(rightFunc.apply(rightVal)); } - - @Override - public <BoundLeft> IPair<BoundLeft, RightType> - bindLeft(final Function<LeftType, IPair<BoundLeft, RightType>> leftBinder) { - if (leftBinder == null) - throw new NullPointerException("Left binder must not be null"); - - if (isLeft) - return leftBinder.apply(leftVal); - - return new Either<>(null, rightVal); + + /** + * Extract the value from this Either. + * + * @param <Common> The common type to extract. + * + * @param leftHandler The function to handle left-values. + * @param rightHandler The function to handle right-values. + * + * @return The result of applying the proper function. + */ + public <Common> Common extract( + Function<LeftType, Common> leftHandler, + Function<RightType, Common> rightHandler) + { + if (isLeft) return leftHandler.apply(leftVal); + else return rightHandler.apply(rightVal); } - - @Override - public <BoundRight> IPair<LeftType, BoundRight> bindRight( - final Function<RightType, IPair<LeftType, BoundRight>> rightBinder) { - if (rightBinder == null) - throw new NullPointerException("Right binder must not be null"); - - if (isLeft) - return new Either<>(leftVal, null); - - return rightBinder.apply(rightVal); + + /** + * Perform an action on this either. + * + * @param leftHandler The handler of left values. + * @param rightHandler The handler of right values. + */ + public void pick( + Consumer<LeftType> leftHandler, Consumer<RightType> rightHandler) + { + if (isLeft) leftHandler.accept(leftVal); + else rightHandler.accept(rightVal); } - @Override - public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> - IPair<CombinedLeft, CombinedRight> - combine(final IPair<OtherLeft, OtherRight> otherPair, - final BiFunction<LeftType, OtherLeft, CombinedLeft> leftCombiner, - final BiFunction<RightType, OtherRight, - CombinedRight> rightCombiner) { - if (otherPair == null) { - throw new NullPointerException("Other pair must not be null"); - } else if (leftCombiner == null) { - throw new NullPointerException("Left combiner must not be null"); - } else if (rightCombiner == null) { - throw new NullPointerException("Right combiner must not be null"); - } - - if (isLeft) { - return otherPair.bind((otherLeft, otherRight) -> { - CombinedLeft cLeft = leftCombiner.apply(leftVal, otherLeft); - - return new Either<>(cLeft, null); - }); - } - - return otherPair.bind((otherLeft, otherRight) -> { - CombinedRight cRight = rightCombiner.apply(rightVal, otherRight); - - return new Either<>(null, cRight); - }); + /** + * Check if this either is left-aligned (has the left value filled, + * not the right value). + * + * @return Whether this either is left-aligned. + */ + public boolean isLeft() { + return isLeft; } - @Override - public <NewLeft> IPair<NewLeft, RightType> - mapLeft(final Function<LeftType, NewLeft> mapper) { - if (mapper == null) - throw new NullPointerException("Mapper must not be null"); - - if (isLeft) - return new Either<>(mapper.apply(leftVal), null); - - return new Either<>(null, rightVal); + /** + * Get the left value of this either if there is one. + * + * @return An optional containing the left value, if there is one. + */ + public Optional<LeftType> getLeft() { + return Optional.ofNullable(leftVal); } - - @Override - public <NewRight> IPair<LeftType, NewRight> - mapRight(final Function<RightType, NewRight> mapper) { - if (mapper == null) - throw new NullPointerException("Mapper must not be null"); - + + /** + * Get the left value of this either, or get a {@link NoSuchElementException} + * if there isn't one. + * + * @return The left value of this either. + * + * @throws NoSuchElementException If this either doesn't have a left value. + */ + public LeftType forceLeft() { if (isLeft) - return new Either<>(leftVal, null); - - return new Either<>(null, mapper.apply(rightVal)); + { + return leftVal; + } else + { + throw new NoSuchElementException("Either has no left value, is right value"); + } } - @Override - public <MergedType> MergedType - merge(final BiFunction<LeftType, RightType, MergedType> merger) { - if (merger == null) - throw new NullPointerException("Merger must not be null"); - - return merger.apply(leftVal, rightVal); + /** + * Get the right value of this either if there is one. + * + * @return An optional containing the right value, if there is one. + */ + public Optional<RightType> getRight() { + return Optional.ofNullable(rightVal); } - + + /** + * Get the right value of this either, or get a {@link NoSuchElementException} + * if there isn't one. + * + * @return The right value of this either. + * + * @throws NoSuchElementException If this either doesn't have a right value. + */ + public RightType forceRight() { + if (isLeft) + { + throw new NoSuchElementException("Either has no right value, has left value"); + } else + { + return rightVal; + } + } + + // Misc. overrides + @Override public int hashCode() { - final int prime = 31; - - int result = 1; - result = prime * result + (isLeft ? 1231 : 1237); - result = prime * result + (leftVal == null ? 0 : leftVal.hashCode()); - result = prime * result + (rightVal == null ? 0 : rightVal.hashCode()); - - return result; + return Objects.hash(isLeft, leftVal, rightVal); } @Override - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof Either<?, ?>)) - return false; - - final Either<?, ?> other = (Either<?, ?>) obj; - - if (isLeft != other.isLeft) - return false; - - if (leftVal == null) { - if (other.leftVal != null) - return false; - } else if (!leftVal.equals(other.leftVal)) - return false; - - if (rightVal == null) { - if (other.rightVal != null) - return false; - } else if (!rightVal.equals(other.rightVal)) - return false; - - return true; + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + + Either<?, ?> other = (Either<?, ?>) obj; + + return isLeft == other.isLeft + && Objects.equals(leftVal, other.leftVal) + && Objects.equals(rightVal, other.rightVal); } @Override diff --git a/src/main/java/bjc/data/GeneratingIterator.java b/src/main/java/bjc/data/GeneratingIterator.java index ffa92cf..f926833 100644 --- a/src/main/java/bjc/data/GeneratingIterator.java +++ b/src/main/java/bjc/data/GeneratingIterator.java @@ -58,4 +58,17 @@ public class GeneratingIterator<E> implements Iterator<E> { return state; } + + /** + * Sets the state of this iterator. + * + * @param newState The new state value. + * + * @return The old state value. + */ + public E setState(E newState) { + E oldState = this.state; + this.state = newState; + return oldState; + } } diff --git a/src/main/java/bjc/data/IHolder.java b/src/main/java/bjc/data/Holder.java index faa3f64..f01812e 100644 --- a/src/main/java/bjc/data/IHolder.java +++ b/src/main/java/bjc/data/Holder.java @@ -18,7 +18,7 @@ import bjc.funcdata.theory.Functor; * @param <ContainedType> * The type of value held. */ -public interface IHolder<ContainedType> extends Functor<ContainedType> { +public interface Holder<ContainedType> extends Functor<ContainedType> { /** * Bind a function across the value in this container. * @@ -30,8 +30,8 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return A holder from binding the value. */ - public <BoundType> IHolder<BoundType> - bind(Function<ContainedType, IHolder<BoundType>> binder); + public <BoundType> Holder<BoundType> + bind(Function<ContainedType, Holder<BoundType>> binder); /** * Apply an action to the value. @@ -51,14 +51,14 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { default <ArgType, ReturnType> Function<Functor<ArgType>, Functor<ReturnType>> fmap(final Function<ArgType, ReturnType> func) { return argumentFunctor -> { - if (!(argumentFunctor instanceof IHolder<?>)) { + if (!(argumentFunctor instanceof Holder<?>)) { final String msg = "This functor only supports mapping over instances of IHolder"; throw new IllegalArgumentException(msg); } - final IHolder<ArgType> holder = (IHolder<ArgType>) argumentFunctor; + final Holder<ArgType> holder = (Holder<ArgType>) argumentFunctor; return holder.map(func); }; @@ -80,7 +80,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return The function lifted over the holder. */ - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(Function<ContainedType, NewType> func); /** @@ -88,7 +88,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return A lazy version of this holder. */ - public default IHolder<ContainedType> makeLazy() { + public default Holder<ContainedType> makeLazy() { return new WrappedLazy<>(this); } @@ -97,7 +97,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return A list version of this holder. */ - public default IHolder<ContainedType> makeList() { + public default Holder<ContainedType> makeList() { return new BoundListHolder<>(new FunctionalList<>(this)); } @@ -106,7 +106,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return An optional version of this holder. */ - public default IHolder<ContainedType> makeOptional() { + public default Holder<ContainedType> makeOptional() { return new WrappedOption<>(this); } @@ -123,7 +123,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return A holder with the mapped value */ - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(Function<ContainedType, MappedType> mapper); /** @@ -134,7 +134,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return The holder itself. */ - public default IHolder<ContainedType> replace(final ContainedType newValue) { + public default Holder<ContainedType> replace(final ContainedType newValue) { return transform(oldValue -> newValue); } @@ -146,7 +146,7 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { * * @return The holder itself, for easy chaining. */ - public IHolder<ContainedType> transform(UnaryOperator<ContainedType> transformer); + public Holder<ContainedType> transform(UnaryOperator<ContainedType> transformer); /** * Unwrap the value contained in this holder so that it is no longer held. @@ -161,4 +161,17 @@ public interface IHolder<ContainedType> extends Functor<ContainedType> { */ public <UnwrappedType> UnwrappedType unwrap(Function<ContainedType, UnwrappedType> unwrapper); + + /** + * Create an instace of IHolder containing a single value. + * + * @param <ElementType> The type of the value contained. + * + * @param contained The value to contain. + * + * @return An instance of IHolder containing that value. + */ + static <ElementType> Holder<ElementType> of(ElementType contained) { + return new Identity<>(contained); + } } diff --git a/src/main/java/bjc/data/IPair.java b/src/main/java/bjc/data/IPair.java deleted file mode 100644 index 5b1298e..0000000 --- a/src/main/java/bjc/data/IPair.java +++ /dev/null @@ -1,249 +0,0 @@ -package bjc.data; - -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Function; - -import bjc.funcdata.theory.Bifunctor; - -/** - * 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> extends Bifunctor<LeftType, RightType> { - /** - * 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); - - /** - * 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); - - /** - * Pairwise combine two pairs together. - * - * @param <OtherLeft> - * The left type of the other pair. - * - * @param <OtherRight> - * The right type of the other pair. - * - * @param otherPair - * The pair to combine with. - * - * @return The pairs, pairwise combined together. - */ - public default <OtherLeft, OtherRight> - IPair<IPair<LeftType, OtherLeft>, IPair<RightType, OtherRight>> - combine(final IPair<OtherLeft, OtherRight> otherPair) { - return combine(otherPair, Pair<LeftType, OtherLeft>::new, - Pair<RightType, OtherRight>::new); - } - - /** - * Combine the contents of two pairs together. - * - * @param <OtherLeft> - * The type of the left value of the other pair. - * - * @param <OtherRight> - * The type of the right value of the other pair. - * - * @param <CombinedLeft> - * The type of the left value of the combined pair. - * - * @param <CombinedRight> - * The type of the right value of the combined pair. - * - * @param otherPair - * The other pair to combine with. - * - * @param leftCombiner - * The function to combine the left values with. - * - * @param rightCombiner - * The function to combine the right values with. - * - * @return A pair with its values combined. - */ - public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> - IPair<CombinedLeft, CombinedRight> - combine(IPair<OtherLeft, OtherRight> otherPair, - BiFunction<LeftType, OtherLeft, CombinedLeft> leftCombiner, - BiFunction<RightType, OtherRight, CombinedRight> rightCombiner); - - /** - * Immediately perfom the specified action with the contents of this pair. - * - * @param consumer - * The action to perform on the pair. - */ - public default void doWith(final BiConsumer<LeftType, RightType> consumer) { - merge((leftValue, rightValue) -> { - consumer.accept(leftValue, rightValue); - - return null; - }); - } - - @Override - default <OldLeft, OldRight, NewLeft> LeftBifunctorMap<OldLeft, OldRight, NewLeft> - fmapLeft(final Function<OldLeft, NewLeft> func) { - return argumentPair -> { - if (!(argumentPair instanceof IPair<?, ?>)) { - final String msg - = "This function can only be applied to instances of IPair"; - - throw new IllegalArgumentException(msg); - } - - final IPair<OldLeft, OldRight> argPair - = (IPair<OldLeft, OldRight>) argumentPair; - - return argPair.mapLeft(func); - }; - } - - @Override - default <OldLeft, OldRight, NewRight> RightBifunctorMap<OldLeft, OldRight, NewRight> - fmapRight(final Function<OldRight, NewRight> func) { - return argumentPair -> { - if (!(argumentPair instanceof IPair<?, ?>)) { - final String msg - = "This function can only be applied to instances of IPair"; - - throw new IllegalArgumentException(msg); - } - - final IPair<OldLeft, OldRight> argPair - = (IPair<OldLeft, OldRight>) argumentPair; - - return argPair.mapRight(func); - }; - } - - /** - * Get the value on the left side of the pair. - * - * @return The value on the left side of the pair. - */ - @Override - 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. - */ - @Override - public default RightType getRight() { - return merge((leftValue, rightValue) -> rightValue); - } - - /** - * Transform the value on the left side of the pair. - * - * Doesn't modify the pair. - * - * @param <NewLeft> - * The new type of the left part of the pair. - * - * @param mapper - * The function to use to transform the left part of the pair. - * - * @return The pair, with its left part transformed. - */ - public <NewLeft> IPair<NewLeft, RightType> - mapLeft(Function<LeftType, NewLeft> mapper); - - /** - * Transform the value on the right side of the pair. - * - * Doesn't modify the pair. - * - * @param <NewRight> - * The new type of the right part of the pair. - * - * @param mapper - * The function to use to transform the right part of the - * pair. - * - * @return The pair, with its right part transformed. - */ - public <NewRight> IPair<LeftType, NewRight> - mapRight(Function<RightType, NewRight> mapper); - - /** - * 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); - - /** - * Static pair constructor. - * - * @param left - * The left side of the pair. - * @param right - * The right side of the pair. - * @return A pair, with the specified left/right side. - */ - public static <T1, T2> IPair<T1, T2> pair(T1 left, T2 right) { - return new Pair<>(left, right); - } -} diff --git a/src/main/java/bjc/data/ITree.java b/src/main/java/bjc/data/ITree.java deleted file mode 100644 index e9c829e..0000000 --- a/src/main/java/bjc/data/ITree.java +++ /dev/null @@ -1,287 +0,0 @@ -package bjc.data; - -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.UnaryOperator; - -import bjc.funcdata.IList; -import bjc.funcdata.bst.TreeLinearizationMethod; - -/** - * A node in a homogeneous tree with a unlimited amount of children. - * - * @author ben - * - * @param <ContainedType> - * The type of data contained in the tree nodes. - * - */ -public interface ITree<ContainedType> { - /** - * Append a child to this node. - * - * @param child - * The child to append to this node. - */ - void addChild(ITree<ContainedType> child); - - /** - * Append a child to this node. - * - * @param child - * The child to append to this node. - */ - void addChild(ContainedType child); - - /** - * Prepend a child to this node. - * - * @param child - * The child to prepend to this node. - */ - void prependChild(ITree<ContainedType> child); - - /** - * Collapse a tree into a single version. - * - * @param <NewType> - * The intermediate type being folded. - * - * @param <ReturnedType> - * The type that is the end result. - * - * @param leafTransform - * The function to use to convert leaf values. - * - * @param nodeCollapser - * The function to use to convert internal nodes and - * their children. - * - * @param resultTransformer - * The function to use to convert a state to the - * returned version. - * - * @return The final transformed state. - */ - <NewType, ReturnedType> ReturnedType collapse( - Function<ContainedType, NewType> leafTransform, - BiFunction<ContainedType, IList<NewType>, NewType> nodeCollapser, - Function<NewType, ReturnedType> resultTransformer); - - /** - * Execute a given action for each of this tree's children. - * - * @param action - * The action to execute for each child. - */ - void doForChildren(Consumer<ITree<ContainedType>> action); - - /** - * Expand the nodes of a tree into trees, and then merge the contents of those - * trees into a single tree. - * - * @param mapper - * The function to use to map values into trees. - * - * @return A tree, with some nodes expanded into trees. - */ - default ITree<ContainedType> - flatMapTree(final Function<ContainedType, ITree<ContainedType>> mapper) { - return topDownTransform(dat -> TopDownTransformResult.PUSHDOWN, node -> { - if (node.getChildrenCount() > 0) { - final ITree<ContainedType> parent = node.transformHead(mapper); - - node.doForChildren(parent::addChild); - - return parent; - } - - return node.transformHead(mapper); - }); - } - - /** - * Get the specified child of this tree. - * - * @param childNo - * The number of the child to get. - * - * @return The specified child of this tree. - */ - default ITree<ContainedType> getChild(final int childNo) { - return transformChild(childNo, child -> child); - } - - /** - * Get a count of the number of direct children this node has. - * - * @return The number of direct children this node has. - */ - int getChildrenCount(); - - /** - * Get a count of the number of direct children this node has. - * - * @return The number of direct children this node has. - */ - default int size() { - return getChildrenCount(); - } - - /** - * Get the data stored in this node. - * - * @return The data stored in this node. - */ - default ContainedType getHead() { - return transformHead(head -> head); - } - - /** - * Rebuild the tree with the same structure, but different nodes. - * - * @param <MappedType> - * The type of the new tree. - * - * @param leafTransformer - * The function to use to transform leaf tokens. - * - * @param internalTransformer - * The function to use to transform internal tokens. - * - * @return The tree, with the nodes changed. - */ - <MappedType> ITree<MappedType> rebuildTree( - Function<ContainedType, MappedType> leafTransformer, - Function<ContainedType, MappedType> internalTransformer); - - /** - * Transform some of the nodes in this tree. - * - * @param nodePicker - * The predicate to use to pick nodes to transform. - * - * @param transformer - * The function to use to transform picked nodes. - */ - void selectiveTransform(Predicate<ContainedType> nodePicker, - UnaryOperator<ContainedType> transformer); - - /** - * Do a top-down transform of the tree. - * - * @param transformPicker - * The function to use to pick how to progress. - * - * @param transformer - * The function used to transform picked subtrees. - * - * @return The tree with the transform applied to picked subtrees. - */ - ITree<ContainedType> topDownTransform( - Function<ContainedType, TopDownTransformResult> transformPicker, - UnaryOperator<ITree<ContainedType>> transformer); - - /** - * Transform one of this nodes children. - * - * @param <TransformedType> - * The type of the transformed value. - * - * @param childNo - * The number of the child to transform. - * - * @param transformer - * The function to use to transform the value. - * - * @return The transformed value. - * - * @throws IllegalArgumentException - * if the childNo is out of bounds (0 <= - * childNo <= childCount()). - */ - <TransformedType> TransformedType transformChild(int childNo, - Function<ITree<ContainedType>, TransformedType> transformer); - - /** - * Transform the value that is the head of this node. - * - * @param <TransformedType> - * The type of the transformed value. - * - * @param transformer - * The function to use to transform the value. - * - * @return The transformed value. - */ - <TransformedType> TransformedType - transformHead(Function<ContainedType, TransformedType> transformer); - - /** - * Transform the tree into a tree with a different type of token. - * - * @param <MappedType> - * The type of the new tree. - * - * @param transformer - * The function to use to transform tokens. - * - * @return A tree with the token types transformed. - */ - default <MappedType> ITree<MappedType> - transformTree(final Function<ContainedType, MappedType> transformer) { - return rebuildTree(transformer, transformer); - } - - /** - * Perform an action on each part of the tree. - * - * @param linearizationMethod - * The way to traverse the tree. - * - * @param action - * The action to perform on each tree node. - */ - void traverse(TreeLinearizationMethod linearizationMethod, - Consumer<ContainedType> action); - - /** - * Find the farthest to right child that satisfies the given predicate. - * - * @param childPred - * The predicate to satisfy. - * - * @return The index of the right-most child that satisfies the predicate, or -1 - * if one doesn't exist. - */ - int revFind(Predicate<ITree<ContainedType>> childPred); - - /** - * Check if this tree contains any nodes that satisfy the predicate. - * - * @param pred - * The predicate to look for. - * - * @return Whether or not any items satisfied the predicate. - */ - default boolean containsMatching(Predicate<ContainedType> pred) { - Toggle<Boolean> tog = new OneWayToggle<>(false, true); - - traverse(TreeLinearizationMethod.POSTORDER, val -> { - if (pred.test(val)) - tog.get(); - }); - - return tog.get(); - } - - /** - * Set the head of the tree. - * - * @param dat - * The value to set as the head of the tree. - */ - void setHead(ContainedType dat); -} diff --git a/src/main/java/bjc/data/Identity.java b/src/main/java/bjc/data/Identity.java index c80c7e1..fc4798e 100644 --- a/src/main/java/bjc/data/Identity.java +++ b/src/main/java/bjc/data/Identity.java @@ -11,7 +11,7 @@ import java.util.function.UnaryOperator; * @param <ContainedType> * The type contained in the holder. */ -public class Identity<ContainedType> implements IHolder<ContainedType> { +public class Identity<ContainedType> implements Holder<ContainedType> { /* The held value. */ private ContainedType heldValue; @@ -31,8 +31,8 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { return binder.apply(heldValue); } @@ -48,26 +48,23 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { @Override public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof Identity)) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof Identity)) return false; final Identity<?> other = (Identity<?>) obj; if (heldValue == null) { - if (other.heldValue != null) - return false; - } else if (!heldValue.equals(other.heldValue)) + if (other.heldValue != null) return false; + } else if (!heldValue.equals(other.heldValue)) { return false; + } return true; } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { return val -> { return new Identity<>(func.apply(val)); @@ -75,7 +72,7 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { return new Identity<>(mapper.apply(heldValue)); } @@ -86,7 +83,7 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { heldValue = transformer.apply(heldValue); @@ -102,8 +99,8 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { /** * Create a new identity container. * - * @param val - * The contained value. + * @param <ContainedType> The type of the contained value. + * @param val The contained value. * * @return A new identity container. */ @@ -113,7 +110,9 @@ public class Identity<ContainedType> implements IHolder<ContainedType> { /** * Create a new empty identity container. - * + * + * @param <ContainedType> The type of the contained value. + * * @return A new empty identity container. */ public static <ContainedType> Identity<ContainedType> id() { diff --git a/src/main/java/bjc/data/IntHolder.java b/src/main/java/bjc/data/IntHolder.java new file mode 100644 index 0000000..2783669 --- /dev/null +++ b/src/main/java/bjc/data/IntHolder.java @@ -0,0 +1,72 @@ +package bjc.data; + +/** + * Utility class for ints by ref. + * + * @author Ben Culkin + */ +public class IntHolder { + /** + * The int value. + */ + public int val; + + /** + * Create a new int-holder set to 0. + */ + public IntHolder() { + val = 0; + } + + /** + * Create a new int-holder set to a value. + * + * @param i + * The value to set the int to. + */ + public IntHolder(int i) { + val = i; + } + + /** + * Increment the value by one, and return it. + * + * @return The value of the holder. + */ + public int incr() { + return incr(1); + } + + /** + * Increment the value by an amount and return it. + * + * @param i + * The amount to increment by. + * + * @return The value of the holder. + */ + public int incr(int i) { + val += 1; + + return val; + } + + /** + * Get the value. + * + * @return The value. + */ + public int get() { + return val; + } + + /** + * Set the value. + * + * @param i + * The value to set it to. + */ + public void set(int i) { + val = i; + } +} diff --git a/src/main/java/bjc/data/Lazy.java b/src/main/java/bjc/data/Lazy.java index a425232..b237935 100644 --- a/src/main/java/bjc/data/Lazy.java +++ b/src/main/java/bjc/data/Lazy.java @@ -6,7 +6,7 @@ import java.util.function.UnaryOperator; import bjc.data.internals.BoundLazy; import bjc.funcdata.FunctionalList; -import bjc.funcdata.IList; +import bjc.funcdata.ListEx; /** * A holder that holds a means to create a value, but doesn't actually compute @@ -17,7 +17,7 @@ import bjc.funcdata.IList; * @param <ContainedType> * The type of the value being held. */ -public class Lazy<ContainedType> implements IHolder<ContainedType> { +public class Lazy<ContainedType> implements Holder<ContainedType> { /* The supplier of the type. */ private Supplier<ContainedType> valueSupplier; /* The actual type value. */ @@ -26,7 +26,7 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { private boolean valueMaterialized; /* The list of pending actions on the value. */ - private IList<UnaryOperator<ContainedType>> actions = new FunctionalList<>(); + private ListEx<UnaryOperator<ContainedType>> actions = new FunctionalList<>(); /** * Create a new lazy value from the specified seed value. @@ -54,41 +54,44 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { /* Create a new value from a supplier and a list of actions. */ private Lazy(final Supplier<ContainedType> supp, - final IList<UnaryOperator<ContainedType>> pendingActions) { + final ListEx<UnaryOperator<ContainedType>> pendingActions) { valueSupplier = supp; actions = pendingActions; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { - final IList<UnaryOperator<ContainedType>> pendingActions = new FunctionalList<>(); + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { + final ListEx<UnaryOperator<ContainedType>> pendingActions = new FunctionalList<>(); - actions.forEach(pendingActions::add); + for (UnaryOperator<ContainedType> action : actions) { + pendingActions.add(action); + } + final Supplier<ContainedType> supplier = () -> { - if (valueMaterialized) - return heldValue; - - return valueSupplier.get(); + if (valueMaterialized) return heldValue; + else return valueSupplier.get(); }; return new BoundLazy<>(() -> new Lazy<>(supplier, pendingActions), binder); } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { return val -> new Lazy<>(func.apply(val)); } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { - final IList<UnaryOperator<ContainedType>> pendingActions = new FunctionalList<>(); - - actions.forEach(pendingActions::add); + final ListEx<UnaryOperator<ContainedType>> pendingActions = new FunctionalList<>(); + + for (UnaryOperator<ContainedType> action : actions) { + pendingActions.add(action); + } return new Lazy<>(() -> { ContainedType currVal = heldValue; @@ -97,7 +100,8 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { currVal = valueSupplier.get(); } - return pendingActions.reduceAux(currVal, UnaryOperator<ContainedType>::apply, + return pendingActions.reduceAux(currVal, + UnaryOperator<ContainedType>::apply, value -> mapper.apply(value)); }); } @@ -107,16 +111,22 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { if (valueMaterialized) { if (actions.isEmpty()) { return String.format("value[v='%s']", heldValue); + } else { + return String.format("value[v='%s'] (has %d pending transforms)", + heldValue, actions.getSize()); } - - return String.format("value[v='%s'] (has pending transforms)", heldValue); } - return "(unmaterialized)"; + if (actions.isEmpty()) { + return"(unmaterialized)"; + } else { + return String.format("(unmaterialized; has %d pending transforms", + actions.getSize()); + } } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { actions.add(transformer); @@ -132,9 +142,9 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { valueMaterialized = true; } - actions.forEach(action -> { - heldValue = action.apply(heldValue); - }); + for (UnaryOperator<ContainedType> action : actions) { + heldValue = action.apply(heldValue); + } actions = new FunctionalList<>(); @@ -155,12 +165,9 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { @Override public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof Lazy<?>)) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof Lazy<?>)) return false; final Lazy<?> other = (Lazy<?>) obj; @@ -169,27 +176,29 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { if (valueMaterialized) { if (heldValue == null) { - if (other.heldValue != null) - return false; - } else if (!heldValue.equals(other.heldValue)) + if (other.heldValue != null) return false; + } else if (!heldValue.equals(other.heldValue)) { return false; - } else + } + } else { return false; + } if (actions == null) { - if (other.actions != null) - return false; - } else if (actions.getSize() > 0 || other.actions.getSize() > 0) + 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. + * + * @param <ContainedType> The type of the contained value. + * + * @param val The value for the lazy container. * * @return A new lazy container holding that value. */ @@ -200,8 +209,9 @@ public class Lazy<ContainedType> implements IHolder<ContainedType> { /** * Create a new lazy container with a suspended value. * - * @param supp - * The suspended value for the lazy container. + * @param <ContainedType> The type of the contained value. + * + * @param supp The suspended value for the lazy container. * * @return A new lazy container that will un-suspend the value when necessary. */ diff --git a/src/main/java/bjc/data/LazyPair.java b/src/main/java/bjc/data/LazyPair.java index e668cd4..048254a 100644 --- a/src/main/java/bjc/data/LazyPair.java +++ b/src/main/java/bjc/data/LazyPair.java @@ -18,7 +18,7 @@ import bjc.data.internals.HalfBoundLazyPair; * @param <RightType> * The type on the right side of the pair. */ -public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> { +public class LazyPair<LeftType, RightType> implements Pair<LeftType, RightType> { /* The supplier for the left value. */ private Supplier<LeftType> leftSupplier; /* The left value. */ @@ -70,17 +70,16 @@ public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> } @Override - public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( - final BiFunction<LeftType, RightType, IPair<BoundLeft, BoundRight>> binder) { + public <BoundLeft, BoundRight> Pair<BoundLeft, BoundRight> bind( + final BiFunction<LeftType, RightType, Pair<BoundLeft, BoundRight>> binder) { return new BoundLazyPair<>(leftSupplier, rightSupplier, binder); } @Override - public <BoundLeft> IPair<BoundLeft, RightType> - bindLeft(final Function<LeftType, IPair<BoundLeft, RightType>> leftBinder) { + public <BoundLeft> Pair<BoundLeft, RightType> + bindLeft(final Function<LeftType, Pair<BoundLeft, RightType>> leftBinder) { final Supplier<LeftType> leftSupp = () -> { - if (leftMaterialized) - return leftValue; + if (leftMaterialized) return leftValue; return leftSupplier.get(); }; @@ -89,11 +88,10 @@ public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> } @Override - public <BoundRight> IPair<LeftType, BoundRight> bindRight( - final Function<RightType, IPair<LeftType, BoundRight>> rightBinder) { + public <BoundRight> Pair<LeftType, BoundRight> bindRight( + final Function<RightType, Pair<LeftType, BoundRight>> rightBinder) { final Supplier<RightType> rightSupp = () -> { - if (rightMaterialized) - return rightValue; + if (rightMaterialized) return rightValue; return rightSupplier.get(); }; @@ -103,17 +101,19 @@ public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> @Override public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> - IPair<CombinedLeft, CombinedRight> - combine(final IPair<OtherLeft, OtherRight> otherPair, + Pair<CombinedLeft, CombinedRight> + combine(final Pair<OtherLeft, OtherRight> otherPair, final BiFunction<LeftType, OtherLeft, CombinedLeft> leftCombiner, final BiFunction<RightType, OtherRight, CombinedRight> rightCombiner) { - return otherPair.bind((otherLeft, otherRight) -> bind((leftVal, rightVal) -> { - final CombinedLeft left = leftCombiner.apply(leftVal, otherLeft); - final CombinedRight right = rightCombiner.apply(rightVal, otherRight); - - return new LazyPair<>(left, right); - })); + return otherPair.bind((otherLeft, otherRight) -> { + return bind((leftVal, rightVal) -> { + final CombinedLeft left = leftCombiner.apply(leftVal, otherLeft); + final CombinedRight right = rightCombiner.apply(rightVal, otherRight); + + return new LazyPair<>(left, right); + }); + }); } @Override @@ -139,18 +139,16 @@ public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> } @Override - public <NewLeft> IPair<NewLeft, RightType> + public <NewLeft> Pair<NewLeft, RightType> mapLeft(final Function<LeftType, NewLeft> mapper) { final Supplier<NewLeft> leftSupp = () -> { - if (leftMaterialized) - return mapper.apply(leftValue); + if (leftMaterialized) return mapper.apply(leftValue); return mapper.apply(leftSupplier.get()); }; final Supplier<RightType> rightSupp = () -> { - if (rightMaterialized) - return rightValue; + if (rightMaterialized) return rightValue; return rightSupplier.get(); }; @@ -159,18 +157,16 @@ public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> } @Override - public <NewRight> IPair<LeftType, NewRight> + public <NewRight> Pair<LeftType, NewRight> mapRight(final Function<RightType, NewRight> mapper) { final Supplier<LeftType> leftSupp = () -> { - if (leftMaterialized) - return leftValue; + if (leftMaterialized) return leftValue; return leftSupplier.get(); }; final Supplier<NewRight> rightSupp = () -> { - if (rightMaterialized) - return mapper.apply(rightValue); + if (rightMaterialized) return mapper.apply(rightValue); return mapper.apply(rightSupplier.get()); }; @@ -231,37 +227,35 @@ public class LazyPair<LeftType, RightType> implements IPair<LeftType, RightType> @Override public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof LazyPair<?, ?>)) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof LazyPair<?, ?>)) return false; final LazyPair<?, ?> other = (LazyPair<?, ?>) obj; - if (leftMaterialized != other.leftMaterialized) - return false; + if (leftMaterialized != other.leftMaterialized) return false; if (leftMaterialized) { if (leftValue == null) { - if (other.leftValue != null) - return false; - } else if (!leftValue.equals(other.leftValue)) + if (other.leftValue != null) return false; + } else if (!leftValue.equals(other.leftValue)) { return false; - } else + } + } else { return false; + } - if (rightMaterialized != other.rightMaterialized) - return false; + if (rightMaterialized != other.rightMaterialized) return false; + if (rightMaterialized) { if (rightValue == null) { - if (other.rightValue != null) - return false; - } else if (!rightValue.equals(other.rightValue)) + if (other.rightValue != null) return false; + } else if (!rightValue.equals(other.rightValue)) { return false; - } else + } + } else { return false; + } return true; } diff --git a/src/main/java/bjc/data/ListHolder.java b/src/main/java/bjc/data/ListHolder.java index ab3bfa8..c8a75ff 100644 --- a/src/main/java/bjc/data/ListHolder.java +++ b/src/main/java/bjc/data/ListHolder.java @@ -5,7 +5,7 @@ import java.util.function.UnaryOperator; import bjc.data.internals.BoundListHolder; import bjc.funcdata.FunctionalList; -import bjc.funcdata.IList; +import bjc.funcdata.ListEx; /** * A holder that represents a set of non-deterministic computations. @@ -15,8 +15,8 @@ import bjc.funcdata.IList; * @param <ContainedType> * The type of contained value. */ -public class ListHolder<ContainedType> implements IHolder<ContainedType> { - private IList<ContainedType> heldValues; +public class ListHolder<ContainedType> implements Holder<ContainedType> { + private ListEx<ContainedType> heldValues; /** * Create a new list holder. @@ -36,34 +36,34 @@ public class ListHolder<ContainedType> implements IHolder<ContainedType> { } /* Create a new holder with values. */ - private ListHolder(final IList<ContainedType> toHold) { + private ListHolder(final ListEx<ContainedType> toHold) { heldValues = toHold; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { - final IList<IHolder<BoundType>> boundValues = heldValues.map(binder); + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { + final ListEx<Holder<BoundType>> boundValues = heldValues.map(binder); return new BoundListHolder<>(boundValues); } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { return val -> new ListHolder<>(new FunctionalList<>(func.apply(val))); } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { - final IList<MappedType> mappedValues = heldValues.map(mapper); + final ListEx<MappedType> mappedValues = heldValues.map(mapper); return new ListHolder<>(mappedValues); } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { heldValues = heldValues.map(transformer); @@ -93,20 +93,17 @@ public class ListHolder<ContainedType> implements IHolder<ContainedType> { @Override public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof ListHolder<?>)) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof ListHolder<?>)) return false; final ListHolder<?> other = (ListHolder<?>) obj; if (heldValues == null) { - if (other.heldValues != null) - return false; - } else if (!heldValues.equals(other.heldValues)) + if (other.heldValues != null) return false; + } else if (!heldValues.equals(other.heldValues)) { return false; + } return true; } diff --git a/src/main/java/bjc/data/NonCMEIterator.java b/src/main/java/bjc/data/NonCMEIterator.java new file mode 100644 index 0000000..88eaa6b --- /dev/null +++ b/src/main/java/bjc/data/NonCMEIterator.java @@ -0,0 +1,54 @@ +package bjc.data; + +import java.util.*; + +/** + * A Iterator which is guaranteed to never throw {@link ConcurrentModificationException}. + * + * The intended use case for this iterator is that you want to be able to modify + * a list you are iterating over, and not get an immediate exception. + * + * Note that using this is an agreement that you will not complain if it behaves + * oddly in the face of you concurrently modifying the list, as this class was + * designed with the usecase of modifying the list from the same thread, without + * invalidating the iterators. After all, there is a reason that most iterator + * types throw that exception. + * + * However, sometimes you want to play with fire, even if you might get burnt. + * This allows you to do so. + * + * @author Ben Culkin + * + * @param <ElementType> The type being iterated over. + */ +public class NonCMEIterator<ElementType> implements Iterator<ElementType> { + /** + * The list being iterated over. + */ + protected final List<ElementType> source; + + /** + * The index of the current item in the list. + */ + protected int currIndex; + + /** + * Create a new iterator which won't throw {@link ConcurrentModificationException} + * + * @param source The list being iterated over. + */ + public NonCMEIterator(List<ElementType> source) { + this.source = source; + this.currIndex = -1; + } + + @Override + public boolean hasNext() { + return currIndex >= source.size(); + } + + @Override + public ElementType next() { + return source.get(++currIndex); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/data/NonCMEListIterator.java b/src/main/java/bjc/data/NonCMEListIterator.java new file mode 100644 index 0000000..6e74a24 --- /dev/null +++ b/src/main/java/bjc/data/NonCMEListIterator.java @@ -0,0 +1,68 @@ +package bjc.data; + +import java.util.*; + +/** + * A ListIterator which is guaranteed to never throw {@link ConcurrentModificationException}. + * + * The intended use case for this iterator is that you want to be able to modify + * a list you are iterating over, and not get an immediate exception. + * + * Note that using this is an agreement that you will not complain if it behaves + * oddly in the face of you concurrently modifying the list, as this class was + * designed with the usecase of modifying the list from the same thread, without + * invalidating the iterators. After all, there is a reason that most iterator + * types throw that exception. + * + * However, sometimes you want to play with fire, even if you might get burnt. + * This allows you to do so. + * + * @author Ben Culkin + * + * @param <ElementType> The type being iterated over. + */ +public class NonCMEListIterator<ElementType> extends NonCMEIterator<ElementType> implements ListIterator<ElementType> { + /** + * Create a new list iterator which won't throw {@link ConcurrentModificationException} + * + * @param source The list to iterate over. + */ + public NonCMEListIterator(List<ElementType> source) { + super(source); + } + + @Override + public boolean hasPrevious() { + return currIndex > 0; + } + + @Override + public ElementType previous() { + return source.get(--currIndex); + } + + @Override + public int nextIndex() { + return currIndex + 1; + } + + @Override + public int previousIndex() { + return currIndex - 1; + } + + @Override + public void remove() { + source.remove(currIndex); + } + + @Override + public void set(ElementType element) { + source.set(currIndex, element); + } + + @Override + public void add(ElementType element) { + source.add(currIndex, element); + } +} diff --git a/src/main/java/bjc/data/OneWayToggle.java b/src/main/java/bjc/data/OneWayToggle.java index c2e9e4b..b6074b0 100644 --- a/src/main/java/bjc/data/OneWayToggle.java +++ b/src/main/java/bjc/data/OneWayToggle.java @@ -31,23 +31,21 @@ public class OneWayToggle<E> implements Toggle<E> { @Override public E get() { - if (gotFirst) - return second; + if (gotFirst) return second; gotFirst = true; + return first; } @Override public E peek() { - if (gotFirst) - return second; - return first; + if (gotFirst) return second; + else return first; } @Override public void set(boolean gotFirst) { this.gotFirst = gotFirst; } - } diff --git a/src/main/java/bjc/data/Option.java b/src/main/java/bjc/data/Option.java index b5d6d5e..6ca8b13 100644 --- a/src/main/java/bjc/data/Option.java +++ b/src/main/java/bjc/data/Option.java @@ -11,9 +11,17 @@ import java.util.function.UnaryOperator; * @param <ContainedType> * The type of the value that may or may not be held. */ -public class Option<ContainedType> implements IHolder<ContainedType> { +public class Option<ContainedType> implements Holder<ContainedType> { private ContainedType held; - + private boolean isHolding; + + /** + * Create a new empty optional. + */ + public Option() { + isHolding = false; + } + /** * Create a new optional, using the given initial value. * @@ -22,38 +30,35 @@ public class Option<ContainedType> implements IHolder<ContainedType> { */ public Option(final ContainedType seed) { held = seed; + isHolding = true; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { - if (held == null) - return new Option<>(null); + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { + if (isHolding) return new Option<>(); return binder.apply(held); } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { return val -> new Option<>(func.apply(val)); } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { - if (held == null) - return new Option<>(null); + if (isHolding) return new Option<>(); return new Option<>(mapper.apply(held)); } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { - if (held != null) { - held = transformer.apply(held); - } + if (isHolding) held = transformer.apply(held); return this; } @@ -61,8 +66,7 @@ public class Option<ContainedType> implements IHolder<ContainedType> { @Override public <UnwrappedType> UnwrappedType unwrap(final Function<ContainedType, UnwrappedType> unwrapper) { - if (held == null) - return null; + if (isHolding) return null; return unwrapper.apply(held); } @@ -84,20 +88,17 @@ public class Option<ContainedType> implements IHolder<ContainedType> { @Override public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof Option<?>)) - return false; + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof Option<?>)) return false; final Option<?> other = (Option<?>) obj; if (held == null) { - if (other.held != null) - return false; - } else if (!held.equals(other.held)) + if (other.held != null) return false; + } else if (!held.equals(other.held)) { return false; + } return true; } diff --git a/src/main/java/bjc/data/Pair.java b/src/main/java/bjc/data/Pair.java index 610e89c..baf1894 100644 --- a/src/main/java/bjc/data/Pair.java +++ b/src/main/java/bjc/data/Pair.java @@ -1,163 +1,250 @@ package bjc.data; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; +import bjc.funcdata.theory.Bifunctor; + /** - * A pair of values, with nothing special about them. + * Represents a pair of values. * * @author ben * * @param <LeftType> - * The type of the left value. + * The type of the left side of the pair. * * @param <RightType> - * The type of the right value. + * The type of the right side of the pair. + * */ -public class Pair<LeftType, RightType> implements IPair<LeftType, RightType> { - /* The left value. */ - private LeftType leftValue; - /* The right value. */ - private RightType rightValue; - - /** Create a new pair with both sides set to null. */ - public Pair() { - - } - +public interface Pair<LeftType, RightType> extends Bifunctor<LeftType, RightType> { /** - * Create a new pair with both sides set to the specified values. + * Bind a function across the values in this pair. * - * @param left - * The value of the left side. + * @param <BoundLeft> + * The type of the bound left. * - * @param right - * The value of the right side. + * @param <BoundRight> + * The type of the bound right. + * + * @param binder + * The function to bind with. + * + * @return The bound pair. */ - public Pair(final LeftType left, final RightType right) { - leftValue = left; - rightValue = right; - } - - @Override - public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( - final BiFunction<LeftType, RightType, IPair<BoundLeft, BoundRight>> binder) { - if (binder == null) - throw new NullPointerException("Binder must not be null."); + public <BoundLeft, BoundRight> Pair<BoundLeft, BoundRight> + bind(BiFunction<LeftType, RightType, Pair<BoundLeft, BoundRight>> binder); - return binder.apply(leftValue, rightValue); - } + /** + * 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> Pair<BoundLeft, RightType> + bindLeft(Function<LeftType, Pair<BoundLeft, RightType>> leftBinder); - @Override - public <BoundLeft> IPair<BoundLeft, RightType> - bindLeft(final Function<LeftType, IPair<BoundLeft, RightType>> leftBinder) { - if (leftBinder == null) - throw new NullPointerException("Binder must not be null"); + /** + * 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> Pair<LeftType, BoundRight> + bindRight(Function<RightType, Pair<LeftType, BoundRight>> rightBinder); - return leftBinder.apply(leftValue); + /** + * Pairwise combine two pairs together. + * + * @param <OtherLeft> + * The left type of the other pair. + * + * @param <OtherRight> + * The right type of the other pair. + * + * @param otherPair + * The pair to combine with. + * + * @return The pairs, pairwise combined together. + */ + public default <OtherLeft, OtherRight> + Pair<Pair<LeftType, OtherLeft>, Pair<RightType, OtherRight>> + combine(final Pair<OtherLeft, OtherRight> otherPair) { + return combine(otherPair, + SimplePair<LeftType, OtherLeft>::new, + SimplePair<RightType, OtherRight>::new); } - @Override - public <BoundRight> IPair<LeftType, BoundRight> bindRight( - final Function<RightType, IPair<LeftType, BoundRight>> rightBinder) { - if (rightBinder == null) - throw new NullPointerException("Binder must not be null"); + /** + * Combine the contents of two pairs together. + * + * @param <OtherLeft> + * The type of the left value of the other pair. + * + * @param <OtherRight> + * The type of the right value of the other pair. + * + * @param <CombinedLeft> + * The type of the left value of the combined pair. + * + * @param <CombinedRight> + * The type of the right value of the combined pair. + * + * @param otherPair + * The other pair to combine with. + * + * @param leftCombiner + * The function to combine the left values with. + * + * @param rightCombiner + * The function to combine the right values with. + * + * @return A pair with its values combined. + */ + public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> + Pair<CombinedLeft, CombinedRight> + combine(Pair<OtherLeft, OtherRight> otherPair, + BiFunction<LeftType, OtherLeft, CombinedLeft> leftCombiner, + BiFunction<RightType, OtherRight, CombinedRight> rightCombiner); - return rightBinder.apply(rightValue); - } + /** + * Immediately perfom the specified action with the contents of this pair. + * + * @param consumer + * The action to perform on the pair. + */ + public default void doWith(final BiConsumer<LeftType, RightType> consumer) { + merge((leftValue, rightValue) -> { + consumer.accept(leftValue, rightValue); - @Override - public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> - IPair<CombinedLeft, CombinedRight> - combine(final IPair<OtherLeft, OtherRight> otherPair, - final BiFunction<LeftType, OtherLeft, CombinedLeft> leftCombiner, - final BiFunction<RightType, OtherRight, - CombinedRight> rightCombiner) { - return otherPair.bind((otherLeft, otherRight) -> { - final CombinedLeft left = leftCombiner.apply(leftValue, otherLeft); - final CombinedRight right = rightCombiner.apply(rightValue, otherRight); - - return new Pair<>(left, right); + return null; }); } @Override - public <NewLeft> IPair<NewLeft, RightType> - mapLeft(final Function<LeftType, NewLeft> mapper) { - if (mapper == null) - throw new NullPointerException("Mapper must not be null"); + default <OldLeft, OldRight, NewLeft> LeftBifunctorMap<OldLeft, OldRight, NewLeft> + fmapLeft(final Function<OldLeft, NewLeft> func) { + return argumentPair -> { + if (!(argumentPair instanceof Pair<?, ?>)) { + final String msg + = "This function can only be applied to instances of IPair"; - return new Pair<>(mapper.apply(leftValue), rightValue); - } + throw new IllegalArgumentException(msg); + } - @Override - public <NewRight> IPair<LeftType, NewRight> - mapRight(final Function<RightType, NewRight> mapper) { - if (mapper == null) - throw new NullPointerException("Mapper must not be null"); + final Pair<OldLeft, OldRight> argPair + = (Pair<OldLeft, OldRight>) argumentPair; - return new Pair<>(leftValue, mapper.apply(rightValue)); + return argPair.mapLeft(func); + }; } @Override - public <MergedType> MergedType - merge(final BiFunction<LeftType, RightType, MergedType> merger) { - if (merger == null) - throw new NullPointerException("Merger must not be null"); + default <OldLeft, OldRight, NewRight> RightBifunctorMap<OldLeft, OldRight, NewRight> + fmapRight(final Function<OldRight, NewRight> func) { + return argumentPair -> { + if (!(argumentPair instanceof Pair<?, ?>)) { + final String msg + = "This function can only be applied to instances of IPair"; - return merger.apply(leftValue, rightValue); - } + throw new IllegalArgumentException(msg); + } - @Override - public String toString() { - return String.format("Pair [leftValue='%s', rightValue='%s']", leftValue, - rightValue); + final Pair<OldLeft, OldRight> argPair + = (Pair<OldLeft, OldRight>) argumentPair; + + return argPair.mapRight(func); + }; } + /** + * Get the value on the left side of the pair. + * + * @return The value on the left side of the pair. + */ @Override - public LeftType getLeft() { - return leftValue; + 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. + */ @Override - public RightType getRight() { - return rightValue; + public default RightType getRight() { + return merge((leftValue, rightValue) -> rightValue); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; + /** + * Transform the value on the left side of the pair. + * + * Doesn't modify the pair. + * + * @param <NewLeft> + * The new type of the left part of the pair. + * + * @param mapper + * The function to use to transform the left part of the pair. + * + * @return The pair, with its left part transformed. + */ + public <NewLeft> Pair<NewLeft, RightType> + mapLeft(Function<LeftType, NewLeft> mapper); - result = prime * result + (leftValue == null ? 0 : leftValue.hashCode()); - result = prime * result + (rightValue == null ? 0 : rightValue.hashCode()); + /** + * Transform the value on the right side of the pair. + * + * Doesn't modify the pair. + * + * @param <NewRight> + * The new type of the right part of the pair. + * + * @param mapper + * The function to use to transform the right part of the + * pair. + * + * @return The pair, with its right part transformed. + */ + public <NewRight> Pair<LeftType, NewRight> + mapRight(Function<RightType, NewRight> mapper); - return result; - } + /** + * 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); - @Override - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof Pair<?, ?>)) - return false; - - final Pair<?, ?> other = (Pair<?, ?>) obj; - - if (leftValue == null) { - if (other.leftValue != null) - return false; - } else if (!leftValue.equals(other.leftValue)) - return false; - - if (rightValue == null) { - if (other.rightValue != null) - return false; - } else if (!rightValue.equals(other.rightValue)) - return false; - - return true; + /** + * Static pair constructor. + * + * @param <Left> The type of the left side. + * @param <Right> The type of the right side. + * @param left The left side of the pair. + * @param right The right side of the pair. + * @return A pair, with the specified left/right side. + */ + public static <Left, Right> Pair<Left, Right> pair(Left left, Right right) { + return new SimplePair<>(left, right); } } diff --git a/src/main/java/bjc/data/QueuedIterator.java b/src/main/java/bjc/data/QueuedIterator.java index f10014e..805fc5e 100644 --- a/src/main/java/bjc/data/QueuedIterator.java +++ b/src/main/java/bjc/data/QueuedIterator.java @@ -9,8 +9,7 @@ import java.util.Iterator; * * @author bjculkin * - * @param <E> - * The type of element this iterator iterates over + * @param <E> The type of element this iterator iterates over */ public class QueuedIterator<E> implements Iterator<E> { private Iterator<E> cur; @@ -19,7 +18,9 @@ public class QueuedIterator<E> implements Iterator<E> { /** * Static method for constructing iterators. - * + * + * @param <E> The type of element this iterator iterates over + * * @return A queued iterator. */ public static <E> QueuedIterator<E> queued() { @@ -29,8 +30,9 @@ public class QueuedIterator<E> implements Iterator<E> { /** * Static method for constructing iterators. * - * @param vals - * The values to iterate over. + * @param <E> The type of element this iterator iterates over + * + * @param vals The values to iterate over. * * @return A queued iterator. */ @@ -42,8 +44,9 @@ public class QueuedIterator<E> implements Iterator<E> { /** * Static method for constructing iterators. * - * @param itrs - * The iterators to use. + * @param <E> The type of element this iterator iterates over + * + * @param itrs The iterators to use. * * @return A queued iterator over the provided iterators. */ @@ -55,8 +58,9 @@ public class QueuedIterator<E> implements Iterator<E> { /** * Static method for constructing iterators. * - * @param itrs - * The iterables to use. + * @param <E> The type of element this iterator iterates over + * + * @param itrs The iterables to use. * * @return A queued iterator over the provided iterables. */ @@ -82,9 +86,7 @@ public class QueuedIterator<E> implements Iterator<E> { public QueuedIterator(Iterator<E>... inits) { this(); - for (Iterator<E> init : inits) { - pending.add(init); - } + for (Iterator<E> init : inits) pending.add(init); } /** @@ -97,9 +99,7 @@ public class QueuedIterator<E> implements Iterator<E> { public QueuedIterator(Iterable<E>... inits) { this(); - for (Iterable<E> init : inits) { - pending.add(init.iterator()); - } + for (Iterable<E> init : inits) pending.add(init.iterator()); } /** @@ -208,8 +208,7 @@ public class QueuedIterator<E> implements Iterator<E> { @Override public boolean hasNext() { while (cur == null || !cur.hasNext()) { - if (pending.isEmpty()) - return false; + if (pending.isEmpty()) return false; cur = pending.pop(); } @@ -220,13 +219,11 @@ public class QueuedIterator<E> implements Iterator<E> { @Override public E next() { while (cur == null || !cur.hasNext()) { - if (pending.isEmpty()) - return null; + if (pending.isEmpty()) return null; cur = pending.pop(); } return cur.next(); } - } diff --git a/src/main/java/bjc/data/ResettableIterator.java b/src/main/java/bjc/data/ResettableIterator.java index 2208fb2..8b7f07a 100644 --- a/src/main/java/bjc/data/ResettableIterator.java +++ b/src/main/java/bjc/data/ResettableIterator.java @@ -56,11 +56,8 @@ public class ResettableIterator<T> implements Iterator<T> { @Override public boolean hasNext() { - if (isRepeating) { - return cacheIterator.hasNext() ? true : backing.hasNext(); - } else { - return backing.hasNext(); - } + if (isRepeating) return cacheIterator.hasNext() ? true : backing.hasNext(); + else return backing.hasNext(); } @Override diff --git a/src/main/java/bjc/data/ReverseListIterator.java b/src/main/java/bjc/data/ReverseListIterator.java new file mode 100644 index 0000000..0b6ec84 --- /dev/null +++ b/src/main/java/bjc/data/ReverseListIterator.java @@ -0,0 +1,72 @@ +package bjc.data; + +import java.util.*; + +/** + * A list iterator which iterates over a list in reverse order. + * + * @author Ben Culkin + * + * @param <Element> The type of element contained. + */ +public class ReverseListIterator<Element> implements ListIterator<Element> +{ + private List<Element> source; + private int currIndex; + + /** + * Create a new reversed iterator from a list. + * + * @param source The list to operate from. + */ + public ReverseListIterator(List<Element> source) + { + this.source = source; + this.currIndex = source.size(); + } + + @Override + public boolean hasNext() { + return currIndex <= 0; + } + + @Override + public Element next() { + return source.get(--currIndex); + } + + @Override + public boolean hasPrevious() { + return currIndex < source.size(); + } + + @Override + public Element previous() { + return source.get(++currIndex); + } + + @Override + public int nextIndex() { + return currIndex - 1; + } + + @Override + public int previousIndex() { + return currIndex + 1; + } + + @Override + public void remove() { + source.remove(currIndex); + } + + @Override + public void set(Element element) { + source.set(currIndex, element); + } + + @Override + public void add(Element element) { + source.add(currIndex, element); + } +} diff --git a/src/main/java/bjc/data/SimplePair.java b/src/main/java/bjc/data/SimplePair.java new file mode 100644 index 0000000..48f5ca3 --- /dev/null +++ b/src/main/java/bjc/data/SimplePair.java @@ -0,0 +1,154 @@ +package bjc.data; + +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 SimplePair<LeftType, RightType> implements Pair<LeftType, RightType> { + /* The left value. */ + private LeftType leftValue; + /* The right value. */ + private RightType rightValue; + + /** Create a new pair with both sides set to null. */ + public SimplePair() { + // Do nothing :) + } + + /** + * 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 SimplePair(final LeftType left, final RightType right) { + leftValue = left; + rightValue = right; + } + + @Override + public <BoundLeft, BoundRight> Pair<BoundLeft, BoundRight> bind( + final BiFunction<LeftType, RightType, Pair<BoundLeft, BoundRight>> binder) { + if (binder == null) throw new NullPointerException("Binder must not be null."); + + return binder.apply(leftValue, rightValue); + } + + @Override + public <BoundLeft> Pair<BoundLeft, RightType> + bindLeft(final Function<LeftType, Pair<BoundLeft, RightType>> leftBinder) { + if (leftBinder == null) throw new NullPointerException("Binder must not be null"); + + return leftBinder.apply(leftValue); + } + + @Override + public <BoundRight> Pair<LeftType, BoundRight> bindRight( + final Function<RightType, Pair<LeftType, BoundRight>> rightBinder) { + if (rightBinder == null) throw new NullPointerException("Binder must not be null"); + + return rightBinder.apply(rightValue); + } + + @Override + public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> + Pair<CombinedLeft, CombinedRight> + combine(final Pair<OtherLeft, OtherRight> otherPair, + final BiFunction<LeftType, OtherLeft, CombinedLeft> leftCombiner, + final BiFunction<RightType, OtherRight, + CombinedRight> rightCombiner) { + return otherPair.bind((otherLeft, otherRight) -> { + final CombinedLeft left = leftCombiner.apply(leftValue, otherLeft); + final CombinedRight right = rightCombiner.apply(rightValue, otherRight); + + return new SimplePair<>(left, right); + }); + } + + @Override + public <NewLeft> Pair<NewLeft, RightType> + mapLeft(final Function<LeftType, NewLeft> mapper) { + if (mapper == null) throw new NullPointerException("Mapper must not be null"); + + return new SimplePair<>(mapper.apply(leftValue), rightValue); + } + + @Override + public <NewRight> Pair<LeftType, NewRight> + mapRight(final Function<RightType, NewRight> mapper) { + if (mapper == null) throw new NullPointerException("Mapper must not be null"); + + return new SimplePair<>(leftValue, mapper.apply(rightValue)); + } + + @Override + public <MergedType> MergedType + merge(final BiFunction<LeftType, RightType, MergedType> merger) { + if (merger == null) throw new NullPointerException("Merger must not be null"); + + return merger.apply(leftValue, rightValue); + } + + @Override + public String toString() { + return String.format("Pair [leftValue='%s', rightValue='%s']", leftValue, + rightValue); + } + + @Override + public LeftType getLeft() { + return leftValue; + } + + @Override + public RightType getRight() { + return rightValue; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + (leftValue == null ? 0 : leftValue.hashCode()); + result = prime * result + (rightValue == null ? 0 : rightValue.hashCode()); + + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof SimplePair<?, ?>)) return false; + + final SimplePair<?, ?> other = (SimplePair<?, ?>) obj; + + if (leftValue == null) { + if (other.leftValue != null) return false; + } else if (!leftValue.equals(other.leftValue)) { + return false; + } + + if (rightValue == null) { + if (other.rightValue != null) return false; + } else if (!rightValue.equals(other.rightValue)) { + return false; + } + + return true; + } +} diff --git a/src/main/java/bjc/data/SimpleTree.java b/src/main/java/bjc/data/SimpleTree.java new file mode 100644 index 0000000..7d9fb6d --- /dev/null +++ b/src/main/java/bjc/data/SimpleTree.java @@ -0,0 +1,446 @@ +package bjc.data; + +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import bjc.funcdata.FunctionalList; +import bjc.funcdata.ListEx; +import bjc.funcdata.bst.TreeLinearizationMethod; + +/** + * A node in a homogeneous tree. + * + * @author ben + * + * @param <ContainedType> + * The type contained in the tree. + */ +public class SimpleTree<ContainedType> implements Tree<ContainedType> { + /* The data/label for this node. */ + private ContainedType data; + + /* The children of this node. */ + private ListEx<Tree<ContainedType>> children; + + /* Whether this node has children. */ + /* + * @NOTE Why have both this boolean and childCount? Why not just do a childCount + * == 0 whenever you'd check hasChildren? + * + * - Because hasChildren is set once and not reset, and really what it + * indicates is that children has been allocated. + */ + private boolean hasChildren; + /* The number of children this node has. */ + private int childCount = 0; + + /* The ID of this node. */ + private int ID; + /* The next ID to assign to a node. */ + private static int nextID = 0; + + /** + * Create a new leaf node in a tree. + */ + public SimpleTree() { + this(null); + } + + /** + * Create a new leaf node in a tree. + * + * @param leaf + * The data to store as a leaf node. + */ + public SimpleTree(final ContainedType leaf) { + data = leaf; + + hasChildren = false; + + ID = nextID++; + } + + /** + * Create a new tree node with the specified children. + * + * @param leaf + * The data to hold in this node. + * + * @param childrn + * A list of children for this node. + */ + public SimpleTree(final ContainedType leaf, final ListEx<Tree<ContainedType>> childrn) { + this(leaf); + + hasChildren = true; + + childCount = childrn.getSize(); + + children = childrn; + } + + /** + * Create a new tree node with the specified children. + * + * @param leaf + * The data to hold in this node. + * + * @param childrn + * A list of children for this node. + */ + @SafeVarargs + public SimpleTree(final ContainedType leaf, final Tree<ContainedType>... childrn) { + this(leaf); + + hasChildren = true; + + childCount = 0; + + children = new FunctionalList<>(); + + for (final Tree<ContainedType> child : childrn) { + children.add(child); + + childCount++; + } + } + + @Override + public void addChild(final ContainedType child) { + addChild(new SimpleTree<>(child)); + } + + @Override + public void addChild(final Tree<ContainedType> child) { + if (hasChildren == false) { + hasChildren = true; + + children = new FunctionalList<>(); + } + + childCount++; + + children.add(child); + } + + @Override + public void prependChild(final Tree<ContainedType> child) { + if (hasChildren == false) { + hasChildren = true; + + children = new FunctionalList<>(); + } + + childCount++; + + children.prepend(child); + } + + @Override + public void doForChildren(final Consumer<Tree<ContainedType>> action) { + if (childCount > 0) children.forEach(action); + } + + @Override + public int getChildrenCount() { + return childCount; + } + + @Override + public int revFind(final Predicate<Tree<ContainedType>> childPred) { + if (childCount == 0) return -1; + + for (int i = childCount - 1; i >= 0; i--) { + if (childPred.test(getChild(i))) return i; + } + + return -1; + } + + @Override + public void traverse(final TreeLinearizationMethod linearizationMethod, + final Consumer<ContainedType> action) { + if (hasChildren) { + switch (linearizationMethod) { + case INORDER: + if (childCount != 2) { + final String msg = "Can only do in-order traversal for binary trees."; + + throw new IllegalArgumentException(msg); + } + + children.getByIndex(0).traverse(linearizationMethod, action); + + action.accept(data); + + children.getByIndex(1).traverse(linearizationMethod, action); + break; + case POSTORDER: + children.forEach(child -> child.traverse(linearizationMethod, action)); + + action.accept(data); + break; + case PREORDER: + action.accept(data); + + children.forEach(child -> child.traverse(linearizationMethod, action)); + break; + default: + break; + + } + } else { + action.accept(data); + } + } + + @Override + public <NewType, ReturnedType> ReturnedType collapse( + final Function<ContainedType, NewType> leafTransform, + final BiFunction<ContainedType, ListEx<NewType>, NewType> nodeCollapser, + final Function<NewType, ReturnedType> resultTransformer) { + return resultTransformer.apply(internalCollapse(leafTransform, nodeCollapser)); + } + + @Override + public Tree<ContainedType> + flatMapTree(final Function<ContainedType, Tree<ContainedType>> mapper) { + if (hasChildren) { + final Tree<ContainedType> flatMappedData = mapper.apply(data); + + final ListEx<Tree<ContainedType>> mappedChildren + = children.map(child -> child.flatMapTree(mapper)); + + mappedChildren.forEach(flatMappedData::addChild); + + return flatMappedData; + } + + return mapper.apply(data); + } + + /* + * Do a collapse of this tree. + */ + + private <NewType> NewType internalCollapse( + final Function<ContainedType, NewType> leafTransform, + final BiFunction<ContainedType, ListEx<NewType>, NewType> nodeCollapser) { + if (hasChildren) { + final ListEx<NewType> collapsedChildren = children.map(child -> { + final NewType collapsed = child.collapse(leafTransform, nodeCollapser, + subTreeVal -> subTreeVal); + + return collapsed; + }); + + return nodeCollapser.apply(data, collapsedChildren); + } + + return leafTransform.apply(data); + } + + private void internalToString(final StringBuilder builder, final int indentLevel, + final boolean initial) { + if (!initial) { + for (int i = 0; i < indentLevel; i++) builder.append(">\t"); + } + + builder.append("Node #"); + builder.append(ID); + builder.append(": "); + builder.append(data == null ? "(null)" : data.toString()); + builder.append("\n"); + + if (hasChildren) { + children.forEach(child -> { + if (child instanceof SimpleTree<?>) { + final SimpleTree<ContainedType> kid = (SimpleTree<ContainedType>) child; + + kid.internalToString(builder, indentLevel + 1, false); + } else { + for (int i = 0; i < indentLevel + 1; i++) { + builder.append(">\t"); + } + + builder.append("Unknown node of type "); + builder.append(child.getClass().getName()); + builder.append("\n"); + } + }); + } + } + + @Override + public <MappedType> Tree<MappedType> rebuildTree( + final Function<ContainedType, MappedType> leafTransformer, + final Function<ContainedType, MappedType> operatorTransformer) { + if (hasChildren) { + final ListEx<Tree<MappedType>> mappedChildren = + children.map(child -> + child.rebuildTree(leafTransformer, operatorTransformer)); + + final MappedType mapData = operatorTransformer.apply(data); + return new SimpleTree<>(mapData, mappedChildren); + } + + return new SimpleTree<>(leafTransformer.apply(data)); + } + + @Override + public void selectiveTransform(final Predicate<ContainedType> nodePicker, + final UnaryOperator<ContainedType> transformer) { + if (hasChildren) { + children.forEach(child -> child.selectiveTransform(nodePicker, transformer)); + } else { + data = transformer.apply(data); + } + } + + @Override + public Tree<ContainedType> topDownTransform( + final Function<ContainedType, TopDownTransformResult> transformPicker, + final UnaryOperator<Tree<ContainedType>> transformer) { + final TopDownTransformResult transformResult = transformPicker.apply(data); + + switch (transformResult) { + case PASSTHROUGH: + Tree<ContainedType> result = new SimpleTree<>(data); + + if (hasChildren) { + children.forEach(child -> { + final Tree<ContainedType> kid + = child.topDownTransform(transformPicker, transformer); + + result.addChild(kid); + }); + } + + return result; + case SKIP: + return this; + case TRANSFORM: + return transformer.apply(this); + case RTRANSFORM: + return transformer.apply(this).topDownTransform(transformPicker, transformer); + case PUSHDOWN: + result = new SimpleTree<>(data); + + if (hasChildren) { + children.forEach(child -> { + final Tree<ContainedType> kid + = child.topDownTransform(transformPicker, transformer); + + result.addChild(kid); + }); + } + + return transformer.apply(result); + case PULLUP: + final Tree<ContainedType> intermediateResult = transformer.apply(this); + + result = new SimpleTree<>(intermediateResult.getHead()); + + intermediateResult.doForChildren(child -> { + final Tree<ContainedType> kid + = child.topDownTransform(transformPicker, transformer); + + result.addChild(kid); + }); + + return result; + default: + final String msg = String.format("Recieved unknown transform result type %s", + transformResult); + + throw new IllegalArgumentException(msg); + } + } + + @Override + public <TransformedType> TransformedType transformChild(final int childNo, + final Function<Tree<ContainedType>, TransformedType> transformer) { + if (childNo < 0 || childNo > childCount - 1) { + final String msg = String.format("Child index #%d is invalid", childNo); + + throw new IllegalArgumentException(msg); + } + + final Tree<ContainedType> selectedKid = children.getByIndex(childNo); + + return transformer.apply(selectedKid); + } + + @Override + public Tree<ContainedType> getChild(final int childNo) { + if (childNo < 0 || childNo > childCount - 1) { + final String msg = String.format("Child index #%d is invalid", childNo); + + throw new IllegalArgumentException(msg); + } + return children.getByIndex(childNo); + } + + @Override + public <TransformedType> TransformedType + transformHead(final Function<ContainedType, TransformedType> transformer) { + return transformer.apply(data); + } + + @Override + public void setHead(ContainedType dat) { + this.data = dat; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + + result = prime * result + childCount; + result = prime * result + (children == null ? 0 : children.hashCode()); + result = prime * result + (data == null ? 0 : data.hashCode()); + + return result; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + + internalToString(builder, 1, true); + + /* Delete a trailing nl. */ + builder.deleteCharAt(builder.length() - 1); + + return builder.toString(); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof SimpleTree<?>)) return false; + + final SimpleTree<?> other = (SimpleTree<?>) obj; + + if (data == null) { + if (other.data != null) return false; + } else if (!data.equals(other.data)) { + return false; + } + + if (childCount != other.childCount) return false; + + if (children == null) { + if (other.children != null) return false; + } else if (!children.equals(other.children)) { + return false; + } + + return true; + } +} diff --git a/src/main/java/bjc/data/TopDownTransformIterator.java b/src/main/java/bjc/data/TopDownTransformIterator.java index 3b4b997..28df590 100644 --- a/src/main/java/bjc/data/TopDownTransformIterator.java +++ b/src/main/java/bjc/data/TopDownTransformIterator.java @@ -26,7 +26,7 @@ import java.util.function.Function; * The type of the nodes in the tree. */ public class TopDownTransformIterator<ContainedType> - implements Iterator<ITree<ContainedType>> { + implements Iterator<Tree<ContainedType>> { /** * Alias type for a tree transformation. * @@ -35,8 +35,8 @@ public class TopDownTransformIterator<ContainedType> * @param <ContainedType> * The type contained in the tree. */ - public interface TreeTransform<ContainedType> extends BiFunction<ITree<ContainedType>, - Consumer<Iterator<ITree<ContainedType>>>, ITree<ContainedType>> { + public interface TreeTransform<ContainedType> extends BiFunction<Tree<ContainedType>, + Consumer<Iterator<Tree<ContainedType>>>, Tree<ContainedType>> { // Alias type; no body is needed } @@ -49,19 +49,19 @@ public class TopDownTransformIterator<ContainedType> */ private final TreeTransform<ContainedType> transform; - private ITree<ContainedType> preParent; - private ITree<ContainedType> postParent; + private Tree<ContainedType> preParent; + private Tree<ContainedType> postParent; - private final Deque<ITree<ContainedType>> preChildren; - private final Deque<ITree<ContainedType>> postChildren; + private final Deque<Tree<ContainedType>> preChildren; + private final Deque<Tree<ContainedType>> postChildren; private TopDownTransformIterator<ContainedType> curChild; private boolean done; private boolean initial; - private final Deque<Iterator<ITree<ContainedType>>> toYield; - private Iterator<ITree<ContainedType>> currYield; + private final Deque<Iterator<Tree<ContainedType>>> toYield; + private Iterator<Tree<ContainedType>> currYield; /** * Create a new tree iterator. @@ -76,7 +76,7 @@ public class TopDownTransformIterator<ContainedType> public TopDownTransformIterator( final Function<ContainedType, TopDownTransformResult> pickr, final TreeTransform<ContainedType> transfrm, - final ITree<ContainedType> tree) { + final Tree<ContainedType> tree) { preParent = tree; preChildren = new LinkedList<>(); @@ -96,10 +96,8 @@ public class TopDownTransformIterator<ContainedType> * @param src * The nodes to yield. */ - public void addYield(final Iterator<ITree<ContainedType>> src) { - if (currYield != null) { - toYield.push(currYield); - } + public void addYield(final Iterator<Tree<ContainedType>> src) { + if (currYield != null) toYield.push(currYield); currYield = src; } @@ -117,7 +115,7 @@ public class TopDownTransformIterator<ContainedType> * * @return The next yielded value. */ - public ITree<ContainedType> flushYields(final ITree<ContainedType> val) { + public Tree<ContainedType> flushYields(final Tree<ContainedType> val) { if (currYield != null) { /* * We have non-sentinel values to yield. @@ -128,9 +126,7 @@ public class TopDownTransformIterator<ContainedType> */ toYield.add(new SingleIterator<>(val)); - if (currYield.hasNext()) { - return currYield.next(); - } + if (currYield.hasNext()) return currYield.next(); while (toYield.size() != 0 && !currYield.hasNext()) { currYield = toYield.pop(); @@ -148,18 +144,16 @@ public class TopDownTransformIterator<ContainedType> } @Override - public ITree<ContainedType> next() { - if (done) - throw new NoSuchElementException(); + public Tree<ContainedType> next() { + if (done) throw new NoSuchElementException(); /* * Flush any values that need to be yielded. */ if (currYield != null) { - ITree<ContainedType> yeld = flushYields(null); + Tree<ContainedType> yeld = flushYields(null); - if (yeld != null) - return yeld; + if (yeld != null) return yeld; } if (initial) { @@ -170,7 +164,7 @@ public class TopDownTransformIterator<ContainedType> switch (res) { case PASSTHROUGH: - postParent = new Tree<>(preParent.getHead()); + postParent = new SimpleTree<>(preParent.getHead()); if (preParent.getChildrenCount() != 0) { for (int i = 0; i < preParent.getChildrenCount(); i++) { @@ -204,12 +198,12 @@ public class TopDownTransformIterator<ContainedType> done = true; return flushYields( - transform.apply(new Tree<>(preParent.getHead()), this::addYield)); + transform.apply(new SimpleTree<>(preParent.getHead()), this::addYield)); case PULLUP: - final ITree<ContainedType> intRes + final Tree<ContainedType> intRes = transform.apply(preParent, this::addYield); - postParent = new Tree<>(intRes.getHead()); + postParent = new SimpleTree<>(intRes.getHead()); if (intRes.getChildrenCount() != 0) { for (int i = 0; i < intRes.getChildrenCount(); i++) { @@ -226,9 +220,7 @@ public class TopDownTransformIterator<ContainedType> throw new IllegalArgumentException("Unknown result type " + res); } - if (res != RTRANSFORM) { - initial = false; - } + if (res != RTRANSFORM) initial = false; } if (curChild == null || !curChild.hasNext()) { @@ -236,22 +228,22 @@ public class TopDownTransformIterator<ContainedType> curChild = new TopDownTransformIterator<>(picker, transform, preChildren.pop()); - final ITree<ContainedType> res = curChild.next(); + final Tree<ContainedType> res = curChild.next(); // System.out.println("\t\tTRACE: adding node " + res + " to children"); postChildren.add(res); return flushYields(res); } - ITree<ContainedType> res = null; + Tree<ContainedType> res = null; if (postParent == null) { - res = new Tree<>(preParent.getHead()); + res = new SimpleTree<>(preParent.getHead()); // System.out.println("\t\tTRACE: adding nodes " + postChildren + " to " + // res); - for (final ITree<ContainedType> child : postChildren) { + for (final Tree<ContainedType> child : postChildren) { res.addChild(child); } @@ -262,7 +254,7 @@ public class TopDownTransformIterator<ContainedType> // System.out.println("\t\tTRACE: adding nodes " + postChildren + " to " + // res); - for (final ITree<ContainedType> child : postChildren) { + for (final Tree<ContainedType> child : postChildren) { res.addChild(child); } } @@ -271,7 +263,7 @@ public class TopDownTransformIterator<ContainedType> return flushYields(res); } - final ITree<ContainedType> res = curChild.next(); + final Tree<ContainedType> res = curChild.next(); // System.out.println("\t\tTRACE: adding node " + res + " to children"); postChildren.add(res); diff --git a/src/main/java/bjc/data/Tree.java b/src/main/java/bjc/data/Tree.java index 9a4caa6..3e16e02 100644 --- a/src/main/java/bjc/data/Tree.java +++ b/src/main/java/bjc/data/Tree.java @@ -6,441 +6,281 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; -import bjc.funcdata.FunctionalList; -import bjc.funcdata.IList; +import bjc.funcdata.ListEx; import bjc.funcdata.bst.TreeLinearizationMethod; /** - * A node in a homogeneous tree. + * A node in a homogeneous tree with a unlimited amount of children. * * @author ben * * @param <ContainedType> - * The type contained in the tree. + * The type of data contained in the tree nodes. + * */ -public class Tree<ContainedType> implements ITree<ContainedType> { - /* The data/label for this node. */ - private ContainedType data; - - /* The children of this node. */ - private IList<ITree<ContainedType>> children; - - /* Whether this node has children. */ - /* - * @NOTE Why have both this boolean and childCount? Why not just do a childCount - * == 0 whenever you'd check hasChildren? - Because hasChildren is set once and - * not reset, and really what it indicates is that children has been allocated. +public interface Tree<ContainedType> { + /** + * Append a child to this node. + * + * @param child + * The child to append to this node. */ - private boolean hasChildren; - /* The number of children this node has. */ - private int childCount = 0; - - /* The ID of this node. */ - private int ID; - /* The next ID to assign to a node. */ - private static int nextID = 0; + void addChild(Tree<ContainedType> child); /** - * Create a new leaf node in a tree. + * Append a child to this node. + * + * @param child + * The child to append to this node. */ - public Tree() { - this(null); - } + void addChild(ContainedType child); /** - * Create a new leaf node in a tree. + * Prepend a child to this node. * - * @param leaf - * The data to store as a leaf node. + * @param child + * The child to prepend to this node. */ - public Tree(final ContainedType leaf) { - data = leaf; - - hasChildren = false; - - ID = nextID++; - } + void prependChild(Tree<ContainedType> child); /** - * Create a new tree node with the specified children. + * Collapse a tree into a single version. + * + * @param <NewType> + * The intermediate type being folded. + * + * @param <ReturnedType> + * The type that is the end result. + * + * @param leafTransform + * The function to use to convert leaf values. + * + * @param nodeCollapser + * The function to use to convert internal nodes and + * their children. * - * @param leaf - * The data to hold in this node. + * @param resultTransformer + * The function to use to convert a state to the + * returned version. * - * @param childrn - * A list of children for this node. + * @return The final transformed state. */ - public Tree(final ContainedType leaf, final IList<ITree<ContainedType>> childrn) { - this(leaf); + <NewType, ReturnedType> ReturnedType collapse( + Function<ContainedType, NewType> leafTransform, + BiFunction<ContainedType, ListEx<NewType>, NewType> nodeCollapser, + Function<NewType, ReturnedType> resultTransformer); - hasChildren = true; - - childCount = childrn.getSize(); - - children = childrn; - } + /** + * Execute a given action for each of this tree's children. + * + * @param action + * The action to execute for each child. + */ + void doForChildren(Consumer<Tree<ContainedType>> action); /** - * Create a new tree node with the specified children. + * Expand the nodes of a tree into trees, and then merge the contents of those + * trees into a single tree. * - * @param leaf - * The data to hold in this node. + * @param mapper + * The function to use to map values into trees. * - * @param childrn - * A list of children for this node. + * @return A tree, with some nodes expanded into trees. */ - @SafeVarargs - public Tree(final ContainedType leaf, final ITree<ContainedType>... childrn) { - this(leaf); - - hasChildren = true; - - childCount = 0; - - children = new FunctionalList<>(); - - for (final ITree<ContainedType> child : childrn) { - children.add(child); - - childCount++; - } - } - - @Override - public void addChild(final ContainedType child) { - addChild(new Tree<>(child)); - } - - @Override - public void addChild(final ITree<ContainedType> child) { - if (hasChildren == false) { - hasChildren = true; + default Tree<ContainedType> + flatMapTree(final Function<ContainedType, Tree<ContainedType>> mapper) { + return topDownTransform(dat -> TopDownTransformResult.PUSHDOWN, node -> { + if (node.getChildrenCount() > 0) { + final Tree<ContainedType> parent = node.transformHead(mapper); - children = new FunctionalList<>(); - } - - childCount++; - - children.add(child); - } - - @Override - public void prependChild(final ITree<ContainedType> child) { - if (hasChildren == false) { - hasChildren = true; - - children = new FunctionalList<>(); - } - - childCount++; - - children.prepend(child); - } - - @Override - public void doForChildren(final Consumer<ITree<ContainedType>> action) { - if (childCount > 0) { - children.forEach(action); - } - } - - @Override - public int getChildrenCount() { - return childCount; - } - - @Override - public int revFind(final Predicate<ITree<ContainedType>> childPred) { - if (childCount == 0) { - return -1; - } - - for (int i = childCount - 1; i >= 0; i--) { - if (childPred.test(getChild(i))) - return i; - } - - return -1; - } - - @Override - public void traverse(final TreeLinearizationMethod linearizationMethod, - final Consumer<ContainedType> action) { - if (hasChildren) { - switch (linearizationMethod) { - case INORDER: - if (childCount != 2) { - final String msg = "Can only do in-order traversal for binary trees."; - - throw new IllegalArgumentException(msg); - } - - children.getByIndex(0).traverse(linearizationMethod, action); - - action.accept(data); - - children.getByIndex(1).traverse(linearizationMethod, action); - break; - case POSTORDER: - children.forEach(child -> child.traverse(linearizationMethod, action)); - - action.accept(data); - break; - case PREORDER: - action.accept(data); - - children.forEach(child -> child.traverse(linearizationMethod, action)); - break; - default: - break; + node.doForChildren(parent::addChild); + return parent; } - } else { - action.accept(data); - } - } - - @Override - public <NewType, ReturnedType> ReturnedType collapse( - final Function<ContainedType, NewType> leafTransform, - final BiFunction<ContainedType, IList<NewType>, NewType> nodeCollapser, - final Function<NewType, ReturnedType> resultTransformer) { - return resultTransformer.apply(internalCollapse(leafTransform, nodeCollapser)); - } - - @Override - public ITree<ContainedType> - flatMapTree(final Function<ContainedType, ITree<ContainedType>> mapper) { - if (hasChildren) { - final ITree<ContainedType> flatMappedData = mapper.apply(data); - - final IList<ITree<ContainedType>> mappedChildren - = children.map(child -> child.flatMapTree(mapper)); - - mappedChildren.forEach(flatMappedData::addChild); - - return flatMappedData; - } - return mapper.apply(data); + return node.transformHead(mapper); + }); } - /* - * Do a collapse of this tree. + /** + * Get the specified child of this tree. + * + * @param childNo + * The number of the child to get. * - * @NOTE Why is this protected? I can't see any good reason someone'd want to - * override it. + * @return The specified child of this tree. */ - - private <NewType> NewType internalCollapse( - final Function<ContainedType, NewType> leafTransform, - final BiFunction<ContainedType, IList<NewType>, NewType> nodeCollapser) { - if (hasChildren) { - final IList<NewType> collapsedChildren = children.map(child -> { - final NewType collapsed = child.collapse(leafTransform, nodeCollapser, - subTreeVal -> subTreeVal); - - return collapsed; - }); - - return nodeCollapser.apply(data, collapsedChildren); - } - - return leafTransform.apply(data); + default Tree<ContainedType> getChild(final int childNo) { + return transformChild(childNo, child -> child); } - private void internalToString(final StringBuilder builder, final int indentLevel, - final boolean initial) { - if (!initial) { - for (int i = 0; i < indentLevel; i++) { - builder.append(">\t"); - } - } - - builder.append("Node #"); - builder.append(ID); - builder.append(": "); - builder.append(data == null ? "(null)" : data.toString()); - builder.append("\n"); - - if (hasChildren) { - children.forEach(child -> { - if (child instanceof Tree<?>) { - final Tree<ContainedType> kid = (Tree<ContainedType>) child; - - kid.internalToString(builder, indentLevel + 1, false); - } else { - for (int i = 0; i < indentLevel + 1; i++) { - builder.append(">\t"); - } - - builder.append("Unknown node of type "); - builder.append(child.getClass().getName()); - builder.append("\n"); - } - }); - } - } - - @Override - public <MappedType> ITree<MappedType> rebuildTree( - final Function<ContainedType, MappedType> leafTransformer, - final Function<ContainedType, MappedType> operatorTransformer) { - if (hasChildren) { - final IList<ITree<MappedType>> mappedChildren = children.map(child -> child.rebuildTree(leafTransformer, operatorTransformer)); - - final MappedType mapData = operatorTransformer.apply(data); - return new Tree<>(mapData, mappedChildren); - } - - return new Tree<>(leafTransformer.apply(data)); - } + /** + * Get a count of the number of direct children this node has. + * + * @return The number of direct children this node has. + */ + int getChildrenCount(); - @Override - public void selectiveTransform(final Predicate<ContainedType> nodePicker, - final UnaryOperator<ContainedType> transformer) { - if (hasChildren) { - children.forEach(child -> child.selectiveTransform(nodePicker, transformer)); - } else { - data = transformer.apply(data); - } + /** + * Get a count of the number of direct children this node has. + * + * @return The number of direct children this node has. + */ + default int size() { + return getChildrenCount(); } - @Override - public ITree<ContainedType> topDownTransform( - final Function<ContainedType, TopDownTransformResult> transformPicker, - final UnaryOperator<ITree<ContainedType>> transformer) { - final TopDownTransformResult transformResult = transformPicker.apply(data); - - switch (transformResult) { - case PASSTHROUGH: - ITree<ContainedType> result = new Tree<>(data); - - if (hasChildren) { - children.forEach(child -> { - final ITree<ContainedType> kid - = child.topDownTransform(transformPicker, transformer); - - result.addChild(kid); - }); - } - - return result; - case SKIP: - return this; - case TRANSFORM: - return transformer.apply(this); - case RTRANSFORM: - return transformer.apply(this).topDownTransform(transformPicker, transformer); - case PUSHDOWN: - result = new Tree<>(data); - - if (hasChildren) { - children.forEach(child -> { - final ITree<ContainedType> kid - = child.topDownTransform(transformPicker, transformer); - - result.addChild(kid); - }); - } - - return transformer.apply(result); - case PULLUP: - final ITree<ContainedType> intermediateResult = transformer.apply(this); - - result = new Tree<>(intermediateResult.getHead()); - - intermediateResult.doForChildren(child -> { - final ITree<ContainedType> kid - = child.topDownTransform(transformPicker, transformer); - - result.addChild(kid); - }); - - return result; - default: - final String msg = String.format("Recieved unknown transform result type %s", - transformResult); - - throw new IllegalArgumentException(msg); - } + /** + * Get the data stored in this node. + * + * @return The data stored in this node. + */ + default ContainedType getHead() { + return transformHead(head -> head); } - @Override - public <TransformedType> TransformedType transformChild(final int childNo, - final Function<ITree<ContainedType>, TransformedType> transformer) { - if (childNo < 0 || childNo > childCount - 1) { - final String msg = String.format("Child index #%d is invalid", childNo); + /** + * Rebuild the tree with the same structure, but different nodes. + * + * @param <MappedType> + * The type of the new tree. + * + * @param leafTransformer + * The function to use to transform leaf tokens. + * + * @param internalTransformer + * The function to use to transform internal tokens. + * + * @return The tree, with the nodes changed. + */ + <MappedType> Tree<MappedType> rebuildTree( + Function<ContainedType, MappedType> leafTransformer, + Function<ContainedType, MappedType> internalTransformer); - throw new IllegalArgumentException(msg); - } + /** + * Transform some of the nodes in this tree. + * + * @param nodePicker + * The predicate to use to pick nodes to transform. + * + * @param transformer + * The function to use to transform picked nodes. + */ + void selectiveTransform(Predicate<ContainedType> nodePicker, + UnaryOperator<ContainedType> transformer); - final ITree<ContainedType> selectedKid = children.getByIndex(childNo); + /** + * Do a top-down transform of the tree. + * + * @param transformPicker + * The function to use to pick how to progress. + * + * @param transformer + * The function used to transform picked subtrees. + * + * @return The tree with the transform applied to picked subtrees. + */ + Tree<ContainedType> topDownTransform( + Function<ContainedType, TopDownTransformResult> transformPicker, + UnaryOperator<Tree<ContainedType>> transformer); - return transformer.apply(selectedKid); - } + /** + * Transform one of this nodes children. + * + * @param <TransformedType> + * The type of the transformed value. + * + * @param childNo + * The number of the child to transform. + * + * @param transformer + * The function to use to transform the value. + * + * @return The transformed value. + * + * @throws IllegalArgumentException + * if the childNo is out of bounds (0 <= + * childNo <= childCount()). + */ + <TransformedType> TransformedType transformChild(int childNo, + Function<Tree<ContainedType>, TransformedType> transformer); - @Override - public <TransformedType> TransformedType - transformHead(final Function<ContainedType, TransformedType> transformer) { - return transformer.apply(data); - } + /** + * Transform the value that is the head of this node. + * + * @param <TransformedType> + * The type of the transformed value. + * + * @param transformer + * The function to use to transform the value. + * + * @return The transformed value. + */ + <TransformedType> TransformedType + transformHead(Function<ContainedType, TransformedType> transformer); - @Override - public void setHead(ContainedType dat) { - this.data = dat; + /** + * Transform the tree into a tree with a different type of token. + * + * @param <MappedType> + * The type of the new tree. + * + * @param transformer + * The function to use to transform tokens. + * + * @return A tree with the token types transformed. + */ + default <MappedType> Tree<MappedType> + transformTree(final Function<ContainedType, MappedType> transformer) { + return rebuildTree(transformer, transformer); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - - result = prime * result + childCount; - result = prime * result + (children == null ? 0 : children.hashCode()); - result = prime * result + (data == null ? 0 : data.hashCode()); - - return result; - } + /** + * Perform an action on each part of the tree. + * + * @param linearizationMethod + * The way to traverse the tree. + * + * @param action + * The action to perform on each tree node. + */ + void traverse(TreeLinearizationMethod linearizationMethod, + Consumer<ContainedType> action); - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); + /** + * Find the farthest to right child that satisfies the given predicate. + * + * @param childPred + * The predicate to satisfy. + * + * @return The index of the right-most child that satisfies the predicate, or -1 + * if one doesn't exist. + */ + int revFind(Predicate<Tree<ContainedType>> childPred); - internalToString(builder, 1, true); + /** + * Check if this tree contains any nodes that satisfy the predicate. + * + * @param pred + * The predicate to look for. + * + * @return Whether or not any items satisfied the predicate. + */ + default boolean containsMatching(Predicate<ContainedType> pred) { + Toggle<Boolean> tog = new OneWayToggle<>(false, true); - /* Delete a trailing nl. */ - builder.deleteCharAt(builder.length() - 1); + traverse(TreeLinearizationMethod.POSTORDER, val -> { + if (pred.test(val)) tog.get(); + }); - return builder.toString(); + return tog.get(); } - @Override - public boolean equals(final Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof Tree<?>)) - return false; - - final Tree<?> other = (Tree<?>) obj; - - if (data == null) { - if (other.data != null) - return false; - } else if (!data.equals(other.data)) - return false; - - if (childCount != other.childCount) - return false; - - if (children == null) { - if (other.children != null) - return false; - } else if (!children.equals(other.children)) - return false; - - return true; - } + /** + * Set the head of the tree. + * + * @param dat + * The value to set as the head of the tree. + */ + void setHead(ContainedType dat); } diff --git a/src/main/java/bjc/data/ValueToggle.java b/src/main/java/bjc/data/ValueToggle.java index 041a2d5..9e4b83b 100644 --- a/src/main/java/bjc/data/ValueToggle.java +++ b/src/main/java/bjc/data/ValueToggle.java @@ -37,20 +37,14 @@ public class ValueToggle<E> implements Toggle<E> { @Override public E get() { - if (alignment.get()) { - return lft; - } - - return rght; + if (alignment.get()) return lft; + else return rght; } @Override public E peek() { - if (alignment.peek()) { - return lft; - } - - return rght; + if (alignment.peek()) return lft; + else return rght; } @Override diff --git a/src/main/java/bjc/data/internals/BoundLazy.java b/src/main/java/bjc/data/internals/BoundLazy.java index a350a2b..0e0e95c 100644 --- a/src/main/java/bjc/data/internals/BoundLazy.java +++ b/src/main/java/bjc/data/internals/BoundLazy.java @@ -4,10 +4,10 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.function.UnaryOperator; -import bjc.data.IHolder; +import bjc.data.Holder; import bjc.data.Lazy; import bjc.funcdata.FunctionalList; -import bjc.funcdata.IList; +import bjc.funcdata.ListEx; /** * Implements a lazy holder that has been bound. @@ -19,21 +19,21 @@ import bjc.funcdata.IList; * The type of the new bound value. */ public class BoundLazy<OldType, BoundContainedType> - implements IHolder<BoundContainedType> { + implements Holder<BoundContainedType> { /* The old value. */ - private final Supplier<IHolder<OldType>> oldSupplier; + private final Supplier<Holder<OldType>> oldSupplier; /* The function to use to transform the old value into a new value. */ - private final Function<OldType, IHolder<BoundContainedType>> binder; + private final Function<OldType, Holder<BoundContainedType>> binder; /* The bound value being held. */ - private IHolder<BoundContainedType> boundHolder; + private Holder<BoundContainedType> boundHolder; /* Whether the bound value has been actualized or not. */ private boolean holderBound; /* Transformations currently pending on the bound value. */ - private final IList<UnaryOperator<BoundContainedType>> actions + private final ListEx<UnaryOperator<BoundContainedType>> actions = new FunctionalList<>(); /** @@ -45,20 +45,20 @@ public class BoundLazy<OldType, BoundContainedType> * @param binder * The function to use to bind the old value to the new one. */ - public BoundLazy(final Supplier<IHolder<OldType>> supp, - final Function<OldType, IHolder<BoundContainedType>> binder) { + public BoundLazy(final Supplier<Holder<OldType>> supp, + final Function<OldType, Holder<BoundContainedType>> binder) { oldSupplier = supp; this.binder = binder; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<BoundContainedType, IHolder<BoundType>> bindr) { + public <BoundType> Holder<BoundType> + bind(final Function<BoundContainedType, Holder<BoundType>> bindr) { if (bindr == null) throw new NullPointerException("Binder must not be null"); /* Prepare a list of pending actions. */ - final IList<UnaryOperator<BoundContainedType>> pendingActions + final ListEx<UnaryOperator<BoundContainedType>> pendingActions = new FunctionalList<>(); for (UnaryOperator<BoundContainedType> pendAct : actions) { @@ -66,8 +66,8 @@ public class BoundLazy<OldType, BoundContainedType> } /* Create the new supplier of a value. */ - final Supplier<IHolder<BoundContainedType>> typeSupplier = () -> { - IHolder<BoundContainedType> oldHolder = boundHolder; + final Supplier<Holder<BoundContainedType>> typeSupplier = () -> { + Holder<BoundContainedType> oldHolder = boundHolder; /* Bind the value if it hasn't been bound before. */ if (!holderBound) { @@ -83,7 +83,7 @@ public class BoundLazy<OldType, BoundContainedType> } @Override - public <NewType> Function<BoundContainedType, IHolder<NewType>> + public <NewType> Function<BoundContainedType, Holder<NewType>> lift(final Function<BoundContainedType, NewType> func) { if (func == null) throw new NullPointerException("Function to lift must not be null"); @@ -94,13 +94,13 @@ public class BoundLazy<OldType, BoundContainedType> } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<BoundContainedType, MappedType> mapper) { if (mapper == null) throw new NullPointerException("Mapper must not be null"); /* Prepare a list of pending actions. */ - final IList<UnaryOperator<BoundContainedType>> pendingActions + final ListEx<UnaryOperator<BoundContainedType>> pendingActions = new FunctionalList<>(); for (UnaryOperator<BoundContainedType> pendAct : actions) { @@ -109,7 +109,7 @@ public class BoundLazy<OldType, BoundContainedType> /* Prepare the new supplier. */ final Supplier<MappedType> typeSupplier = () -> { - IHolder<BoundContainedType> oldHolder = boundHolder; + Holder<BoundContainedType> oldHolder = boundHolder; /* Bound the value if it hasn't been bound. */ if (!holderBound) { @@ -133,7 +133,7 @@ public class BoundLazy<OldType, BoundContainedType> } @Override - public IHolder<BoundContainedType> + public Holder<BoundContainedType> transform(final UnaryOperator<BoundContainedType> transformer) { if (transformer == null) throw new NullPointerException("Transformer must not be null"); diff --git a/src/main/java/bjc/data/internals/BoundLazyPair.java b/src/main/java/bjc/data/internals/BoundLazyPair.java index e081c04..91981de 100644 --- a/src/main/java/bjc/data/internals/BoundLazyPair.java +++ b/src/main/java/bjc/data/internals/BoundLazyPair.java @@ -4,8 +4,8 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; -import bjc.data.IHolder; -import bjc.data.IPair; +import bjc.data.Holder; +import bjc.data.Pair; import bjc.data.Identity; import bjc.data.LazyPair; @@ -16,17 +16,17 @@ import bjc.data.LazyPair; */ @SuppressWarnings("javadoc") public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> - implements IPair<NewLeft, NewRight> { + implements Pair<NewLeft, NewRight> { /* The supplier of the left value. */ private final Supplier<OldLeft> leftSupplier; /* The supplier of the right value. */ private final Supplier<OldRight> rightSupplier; /* The binder to transform values. */ - private final BiFunction<OldLeft, OldRight, IPair<NewLeft, NewRight>> binder; + private final BiFunction<OldLeft, OldRight, Pair<NewLeft, NewRight>> binder; /* The bound pair. */ - private IPair<NewLeft, NewRight> boundPair; + private Pair<NewLeft, NewRight> boundPair; /* Whether the pair has been bound yet. */ private boolean pairBound; @@ -46,20 +46,20 @@ public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> */ public BoundLazyPair(final Supplier<OldLeft> leftSupp, final Supplier<OldRight> rightSupp, - final BiFunction<OldLeft, OldRight, IPair<NewLeft, NewRight>> bindr) { + final BiFunction<OldLeft, OldRight, Pair<NewLeft, NewRight>> bindr) { leftSupplier = leftSupp; rightSupplier = rightSupp; binder = bindr; } @Override - public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( - final BiFunction<NewLeft, NewRight, IPair<BoundLeft, BoundRight>> bindr) { + public <BoundLeft, BoundRight> Pair<BoundLeft, BoundRight> bind( + final BiFunction<NewLeft, NewRight, Pair<BoundLeft, BoundRight>> bindr) { if (bindr == null) throw new NullPointerException("Binder must not be null"); - final IHolder<IPair<NewLeft, NewRight>> newPair = new Identity<>(boundPair); - final IHolder<Boolean> newPairMade = new Identity<>(pairBound); + final Holder<Pair<NewLeft, NewRight>> newPair = new Identity<>(boundPair); + final Holder<Boolean> newPairMade = new Identity<>(pairBound); final Supplier<NewLeft> leftSupp = () -> { if (!newPairMade.getValue()) { @@ -91,13 +91,13 @@ public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> } @Override - public <BoundLeft> IPair<BoundLeft, NewRight> - bindLeft(final Function<NewLeft, IPair<BoundLeft, NewRight>> leftBinder) { + public <BoundLeft> Pair<BoundLeft, NewRight> + bindLeft(final Function<NewLeft, Pair<BoundLeft, NewRight>> leftBinder) { if (leftBinder == null) throw new NullPointerException("Left binder must not be null"); final Supplier<NewLeft> leftSupp = () -> { - IPair<NewLeft, NewRight> newPair = boundPair; + Pair<NewLeft, NewRight> newPair = boundPair; if (!pairBound) { /* @@ -113,13 +113,13 @@ public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> } @Override - public <BoundRight> IPair<NewLeft, BoundRight> - bindRight(final Function<NewRight, IPair<NewLeft, BoundRight>> rightBinder) { + public <BoundRight> Pair<NewLeft, BoundRight> + bindRight(final Function<NewRight, Pair<NewLeft, BoundRight>> rightBinder) { if (rightBinder == null) throw new NullPointerException("Right binder must not be null"); final Supplier<NewRight> rightSupp = () -> { - IPair<NewLeft, NewRight> newPair = boundPair; + Pair<NewLeft, NewRight> newPair = boundPair; if (!pairBound) { /* @@ -136,8 +136,8 @@ public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> @Override public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> - IPair<CombinedLeft, CombinedRight> - combine(final IPair<OtherLeft, OtherRight> otherPair, + Pair<CombinedLeft, CombinedRight> + combine(final Pair<OtherLeft, OtherRight> otherPair, final BiFunction<NewLeft, OtherLeft, CombinedLeft> leftCombiner, final BiFunction<NewRight, OtherRight, CombinedRight> rightCombiner) { if (otherPair == null) { @@ -157,7 +157,7 @@ public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> } @Override - public <NewLeftType> IPair<NewLeftType, NewRight> + public <NewLeftType> Pair<NewLeftType, NewRight> mapLeft(final Function<NewLeft, NewLeftType> mapper) { if (mapper == null) throw new NullPointerException("Mapper must not be null"); @@ -184,7 +184,7 @@ public class BoundLazyPair<OldLeft, OldRight, NewLeft, NewRight> } @Override - public <NewRightType> IPair<NewLeft, NewRightType> + public <NewRightType> Pair<NewLeft, NewRightType> mapRight(final Function<NewRight, NewRightType> mapper) { if (mapper == null) throw new NullPointerException("Mapper must not be null"); diff --git a/src/main/java/bjc/data/internals/BoundListHolder.java b/src/main/java/bjc/data/internals/BoundListHolder.java index 1193c8d..c944252 100644 --- a/src/main/java/bjc/data/internals/BoundListHolder.java +++ b/src/main/java/bjc/data/internals/BoundListHolder.java @@ -3,9 +3,9 @@ package bjc.data.internals; import java.util.function.Function; import java.util.function.UnaryOperator; -import bjc.data.IHolder; +import bjc.data.Holder; import bjc.data.ListHolder; -import bjc.funcdata.IList; +import bjc.funcdata.ListEx; /** * Holds a list, converted into a holder. @@ -13,9 +13,9 @@ import bjc.funcdata.IList; * @author Ben Culkin */ @SuppressWarnings("javadoc") -public class BoundListHolder<ContainedType> implements IHolder<ContainedType> { +public class BoundListHolder<ContainedType> implements Holder<ContainedType> { /* The list of contained holders. */ - private final IList<IHolder<ContainedType>> heldHolders; + private final ListEx<Holder<ContainedType>> heldHolders; /** * Create a new list of holders. @@ -23,17 +23,17 @@ public class BoundListHolder<ContainedType> implements IHolder<ContainedType> { * @param toHold * The list of holders to, well, hold. */ - public BoundListHolder(final IList<IHolder<ContainedType>> toHold) { + public BoundListHolder(final ListEx<Holder<ContainedType>> toHold) { heldHolders = toHold; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { if (binder == null) throw new NullPointerException("Binder must not be null"); - final IList<IHolder<BoundType>> boundHolders + final ListEx<Holder<BoundType>> boundHolders = heldHolders.map(containedHolder -> { return containedHolder.bind(binder); }); @@ -42,7 +42,7 @@ public class BoundListHolder<ContainedType> implements IHolder<ContainedType> { } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { if (func == null) throw new NullPointerException("Function to lift must not be null"); @@ -53,12 +53,12 @@ public class BoundListHolder<ContainedType> implements IHolder<ContainedType> { } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { if (mapper == null) throw new NullPointerException("Mapper must not be null"); - final IList<IHolder<MappedType>> mappedHolders + final ListEx<Holder<MappedType>> mappedHolders = heldHolders.map(containedHolder -> { return containedHolder.map(mapper); }); @@ -67,7 +67,7 @@ public class BoundListHolder<ContainedType> implements IHolder<ContainedType> { } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { if (transformer == null) throw new NullPointerException("Transformer must not be null"); diff --git a/src/main/java/bjc/data/internals/HalfBoundLazyPair.java b/src/main/java/bjc/data/internals/HalfBoundLazyPair.java index 6bcb6ae..849b973 100644 --- a/src/main/java/bjc/data/internals/HalfBoundLazyPair.java +++ b/src/main/java/bjc/data/internals/HalfBoundLazyPair.java @@ -4,8 +4,8 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; -import bjc.data.IHolder; -import bjc.data.IPair; +import bjc.data.Holder; +import bjc.data.Pair; import bjc.data.Identity; import bjc.data.LazyPair; @@ -24,15 +24,15 @@ import bjc.data.LazyPair; */ @SuppressWarnings("javadoc") public class HalfBoundLazyPair<OldType, NewLeft, NewRight> - implements IPair<NewLeft, NewRight> { + implements Pair<NewLeft, NewRight> { /* The supplier of the old value. */ private final Supplier<OldType> oldSupplier; /* The function to transform the old value into a new pair. */ - private final Function<OldType, IPair<NewLeft, NewRight>> binder; + private final Function<OldType, Pair<NewLeft, NewRight>> binder; /* The new bound pair. */ - private IPair<NewLeft, NewRight> boundPair; + private Pair<NewLeft, NewRight> boundPair; /* Has the pair been bound yet or not? */ private boolean pairBound; @@ -46,16 +46,16 @@ public class HalfBoundLazyPair<OldType, NewLeft, NewRight> * The function to use to create the pair from the old value. */ public HalfBoundLazyPair(final Supplier<OldType> oldSupp, - final Function<OldType, IPair<NewLeft, NewRight>> bindr) { + final Function<OldType, Pair<NewLeft, NewRight>> bindr) { oldSupplier = oldSupp; binder = bindr; } @Override - public <BoundLeft, BoundRight> IPair<BoundLeft, BoundRight> bind( - final BiFunction<NewLeft, NewRight, IPair<BoundLeft, BoundRight>> bindr) { - final IHolder<IPair<NewLeft, NewRight>> newPair = new Identity<>(boundPair); - final IHolder<Boolean> newPairMade = new Identity<>(pairBound); + public <BoundLeft, BoundRight> Pair<BoundLeft, BoundRight> bind( + final BiFunction<NewLeft, NewRight, Pair<BoundLeft, BoundRight>> bindr) { + final Holder<Pair<NewLeft, NewRight>> newPair = new Identity<>(boundPair); + final Holder<Boolean> newPairMade = new Identity<>(pairBound); final Supplier<NewLeft> leftSupp = () -> { if (!newPairMade.getValue()) { @@ -81,10 +81,10 @@ public class HalfBoundLazyPair<OldType, NewLeft, NewRight> } @Override - public <BoundLeft> IPair<BoundLeft, NewRight> - bindLeft(final Function<NewLeft, IPair<BoundLeft, NewRight>> leftBinder) { + public <BoundLeft> Pair<BoundLeft, NewRight> + bindLeft(final Function<NewLeft, Pair<BoundLeft, NewRight>> leftBinder) { final Supplier<NewLeft> leftSupp = () -> { - IPair<NewLeft, NewRight> newPair = boundPair; + Pair<NewLeft, NewRight> newPair = boundPair; if (!pairBound) { newPair = binder.apply(oldSupplier.get()); @@ -97,10 +97,10 @@ public class HalfBoundLazyPair<OldType, NewLeft, NewRight> } @Override - public <BoundRight> IPair<NewLeft, BoundRight> - bindRight(final Function<NewRight, IPair<NewLeft, BoundRight>> rightBinder) { + public <BoundRight> Pair<NewLeft, BoundRight> + bindRight(final Function<NewRight, Pair<NewLeft, BoundRight>> rightBinder) { final Supplier<NewRight> rightSupp = () -> { - IPair<NewLeft, NewRight> newPair = boundPair; + Pair<NewLeft, NewRight> newPair = boundPair; if (!pairBound) { newPair = binder.apply(oldSupplier.get()); @@ -114,8 +114,8 @@ public class HalfBoundLazyPair<OldType, NewLeft, NewRight> @Override public <OtherLeft, OtherRight, CombinedLeft, CombinedRight> - IPair<CombinedLeft, CombinedRight> - combine(final IPair<OtherLeft, OtherRight> otherPair, + Pair<CombinedLeft, CombinedRight> + combine(final Pair<OtherLeft, OtherRight> otherPair, final BiFunction<NewLeft, OtherLeft, CombinedLeft> leftCombiner, final BiFunction<NewRight, OtherRight, CombinedRight> rightCombiner) { return otherPair.bind((otherLeft, otherRight) -> bind((leftVal, rightVal) -> { @@ -127,7 +127,7 @@ public class HalfBoundLazyPair<OldType, NewLeft, NewRight> } @Override - public <NewLeftType> IPair<NewLeftType, NewRight> + public <NewLeftType> Pair<NewLeftType, NewRight> mapLeft(final Function<NewLeft, NewLeftType> mapper) { final Supplier<NewLeftType> leftSupp = () -> { if (pairBound) @@ -149,7 +149,7 @@ public class HalfBoundLazyPair<OldType, NewLeft, NewRight> } @Override - public <NewRightType> IPair<NewLeft, NewRightType> + public <NewRightType> Pair<NewLeft, NewRightType> mapRight(final Function<NewRight, NewRightType> mapper) { final Supplier<NewLeft> leftSupp = () -> { if (pairBound) diff --git a/src/main/java/bjc/data/internals/WrappedLazy.java b/src/main/java/bjc/data/internals/WrappedLazy.java index cda86fd..624fb1b 100644 --- a/src/main/java/bjc/data/internals/WrappedLazy.java +++ b/src/main/java/bjc/data/internals/WrappedLazy.java @@ -3,7 +3,7 @@ package bjc.data.internals; import java.util.function.Function; import java.util.function.UnaryOperator; -import bjc.data.IHolder; +import bjc.data.Holder; import bjc.data.Lazy; /** @@ -13,9 +13,9 @@ import bjc.data.Lazy; * @param <ContainedType> * The type of the wrapped value. */ -public class WrappedLazy<ContainedType> implements IHolder<ContainedType> { +public class WrappedLazy<ContainedType> implements Holder<ContainedType> { /* Held value. */ - private final IHolder<IHolder<ContainedType>> held; + private final Holder<Holder<ContainedType>> held; /** * Create a new wrapped lazy value. @@ -23,7 +23,7 @@ public class WrappedLazy<ContainedType> implements IHolder<ContainedType> { * @param wrappedHolder * The holder to make lazy. */ - public WrappedLazy(final IHolder<ContainedType> wrappedHolder) { + public WrappedLazy(final Holder<ContainedType> wrappedHolder) { held = new Lazy<>(wrappedHolder); } @@ -34,15 +34,15 @@ public class WrappedLazy<ContainedType> implements IHolder<ContainedType> { * This is a case where reified generics would be useful, because then the * compiler could know which one we meant without the dummy parameter. */ - private WrappedLazy(final IHolder<IHolder<ContainedType>> wrappedHolder, + private WrappedLazy(final Holder<Holder<ContainedType>> wrappedHolder, @SuppressWarnings("unused") final boolean dummy) { held = wrappedHolder; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { - final IHolder<IHolder<BoundType>> newHolder = held.map(containedHolder -> { + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { + final Holder<Holder<BoundType>> newHolder = held.map(containedHolder -> { return containedHolder.bind(binder); }); @@ -50,7 +50,7 @@ public class WrappedLazy<ContainedType> implements IHolder<ContainedType> { } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { return val -> { return new Lazy<>(func.apply(val)); @@ -58,9 +58,9 @@ public class WrappedLazy<ContainedType> implements IHolder<ContainedType> { } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { - final IHolder<IHolder<MappedType>> newHolder = held.map(containedHolder -> { + final Holder<Holder<MappedType>> newHolder = held.map(containedHolder -> { return containedHolder.map(mapper); }); @@ -68,7 +68,7 @@ public class WrappedLazy<ContainedType> implements IHolder<ContainedType> { } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { held.transform(containedHolder -> { return containedHolder.transform(transformer); diff --git a/src/main/java/bjc/data/internals/WrappedOption.java b/src/main/java/bjc/data/internals/WrappedOption.java index 6becc16..f46d501 100644 --- a/src/main/java/bjc/data/internals/WrappedOption.java +++ b/src/main/java/bjc/data/internals/WrappedOption.java @@ -3,7 +3,7 @@ package bjc.data.internals; import java.util.function.Function; import java.util.function.UnaryOperator; -import bjc.data.IHolder; +import bjc.data.Holder; import bjc.data.Option; /** @@ -13,9 +13,9 @@ import bjc.data.Option; * @param <ContainedType> * The wrapped type. */ -public class WrappedOption<ContainedType> implements IHolder<ContainedType> { +public class WrappedOption<ContainedType> implements Holder<ContainedType> { /* The held value. */ - private final IHolder<IHolder<ContainedType>> held; + private final Holder<Holder<ContainedType>> held; /** * Create a new wrapped option. @@ -23,7 +23,7 @@ public class WrappedOption<ContainedType> implements IHolder<ContainedType> { * @param seedValue * The value to wrap. */ - public WrappedOption(final IHolder<ContainedType> seedValue) { + public WrappedOption(final Holder<ContainedType> seedValue) { held = new Option<>(seedValue); } @@ -31,15 +31,15 @@ public class WrappedOption<ContainedType> implements IHolder<ContainedType> { * The dummy parameter is to ensure the compiler can pick the right method, * because without this method erases to the same type as the public one. */ - private WrappedOption(final IHolder<IHolder<ContainedType>> toHold, + private WrappedOption(final Holder<Holder<ContainedType>> toHold, @SuppressWarnings("unused") final boolean dummy) { held = toHold; } @Override - public <BoundType> IHolder<BoundType> - bind(final Function<ContainedType, IHolder<BoundType>> binder) { - final IHolder<IHolder<BoundType>> newHolder = held.map(containedHolder -> { + public <BoundType> Holder<BoundType> + bind(final Function<ContainedType, Holder<BoundType>> binder) { + final Holder<Holder<BoundType>> newHolder = held.map(containedHolder -> { return containedHolder.bind((containedValue) -> { if (containedValue == null) return new Option<>(null); @@ -52,7 +52,7 @@ public class WrappedOption<ContainedType> implements IHolder<ContainedType> { } @Override - public <NewType> Function<ContainedType, IHolder<NewType>> + public <NewType> Function<ContainedType, Holder<NewType>> lift(final Function<ContainedType, NewType> func) { return val -> { return new Option<>(func.apply(val)); @@ -60,9 +60,9 @@ public class WrappedOption<ContainedType> implements IHolder<ContainedType> { } @Override - public <MappedType> IHolder<MappedType> + public <MappedType> Holder<MappedType> map(final Function<ContainedType, MappedType> mapper) { - final IHolder<IHolder<MappedType>> newHolder = held.map(containedHolder -> { + final Holder<Holder<MappedType>> newHolder = held.map(containedHolder -> { return containedHolder.map((containedValue) -> { if (containedValue == null) return null; @@ -75,7 +75,7 @@ public class WrappedOption<ContainedType> implements IHolder<ContainedType> { } @Override - public IHolder<ContainedType> + public Holder<ContainedType> transform(final UnaryOperator<ContainedType> transformer) { held.transform(containedHolder -> { return containedHolder.transform((containedValue) -> { |
