diff options
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils')
30 files changed, 1153 insertions, 483 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GeneralCommandMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GeneralCommandMode.java index 4a41c1c..880e8c5 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/GeneralCommandMode.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GeneralCommandMode.java @@ -1,10 +1,11 @@ package bjc.utils.cli; -import java.util.HashMap; -import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Consumer; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalMap; + /** * A general command mode, with a customizable set of commands * @@ -16,17 +17,19 @@ import java.util.function.Consumer; * */ public class GeneralCommandMode implements ICommandMode { - private Map<String, ICommandHandler> commandHandlers; - private String customPrompt; + private IFunctionalMap<String, ICommand> commandHandlers; + private IFunctionalMap<String, ICommand> defaultHandlers; + + private IFunctionalMap<String, ICommandHelp> helpTopics; - private Map<String, ICommandHandler> defaultHandlers; + private BiConsumer<String, String[]> unknownCommandHandler; - private Consumer<String> errorOutput; - private String modeName; + private Consumer<String> errorOutput; + private Consumer<String> normalOutput; - private Consumer<String> normalOutput; + private String modeName; - private BiConsumer<String, String[]> unknownCommandHandler; + private String customPrompt; /** * Create a new general command mode @@ -41,20 +44,35 @@ public class GeneralCommandMode implements ICommandMode { this.normalOutput = normalOutput; this.errorOutput = errorOutput; - commandHandlers = new HashMap<>(); - defaultHandlers = new HashMap<>(); + commandHandlers = new FunctionalMap<>(); + defaultHandlers = new FunctionalMap<>(); - defaultHandlers.put("list", (args) -> { + defaultHandlers.put("list", new GenericCommand((args) -> { listCommands(); return this; - }); + }, "list\tList available command", + "Lists all of the commands available in this mode," + + " as well as the commands that are valid in any mode.")); - defaultHandlers.put("alias", (args) -> { + defaultHandlers.put("alias", new GenericCommand((args) -> { aliasCommands(args); return this; - }); + }, "alias\tAlias one command to another", + "alias gives a command another name it can be invoked by. It is invoked" + + " with two arguments, the name of the command to alias" + + ", and the alias to give that command.")); + + defaultHandlers.put("help", new GenericCommand((args) -> { + // TODO implement help system + return this; + }, "help\tConsult the help system", + "help consults the internal help system." + + " It can be invoked in two ways. Invoking it with no arguments" + + " causes it to print out all the topics you can ask for details on," + + " while invoking it with the name of a topic will print the entry" + + " for that topic")); } /** @@ -100,8 +118,7 @@ public class GeneralCommandMode implements ICommandMode { * if the specified command already has a handler * registered */ - public void addCommandHandler(String command, - ICommandHandler handler) { + public void addCommandHandler(String command, ICommand handler) { if (command == null) { throw new NullPointerException("Command must not be null"); } else if (handler == null) { @@ -162,14 +179,14 @@ public class GeneralCommandMode implements ICommandMode { normalOutput.accept( "The available commands for this mode are as follows:\n"); - commandHandlers.keySet().forEach((commandName) -> { + commandHandlers.keyList().forEach((commandName) -> { normalOutput.accept("\t" + commandName); }); normalOutput.accept( "\nThe following commands are available in all modes:\n"); - defaultHandlers.keySet().forEach((commandName) -> { + defaultHandlers.keyList().forEach((commandName) -> { normalOutput.accept("\t" + commandName); }); @@ -181,14 +198,11 @@ public class GeneralCommandMode implements ICommandMode { normalOutput.accept("\n"); if (defaultHandlers.containsKey(command)) { - return defaultHandlers.get(command).handle(args); + return defaultHandlers.get(command).getHandler().handle(args); } else if (commandHandlers.containsKey(command)) { - return commandHandlers.get(command).handle(args); + return commandHandlers.get(command).getHandler().handle(args); } else { - if (unknownCommandHandler == null) { - throw new UnsupportedOperationException( - "Command " + command + " is invalid."); - } else if (args != null) { + if (args != null) { errorOutput.accept("ERROR: Unrecognized command " + command + String.join(" ", args)); } else { @@ -196,6 +210,11 @@ public class GeneralCommandMode implements ICommandMode { .accept("ERROR: Unrecognized command " + command); } + if (unknownCommandHandler == null) { + throw new UnsupportedOperationException( + "Command " + command + " is invalid."); + } + unknownCommandHandler.accept(command, args); } diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java new file mode 100644 index 0000000..99951cc --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java @@ -0,0 +1,59 @@ +package bjc.utils.cli; + +/** + * Generic command implementation + * + * @author ben + * + */ +public class GenericCommand implements ICommand { + private static class GenericHelp implements ICommandHelp { + private String summary; + private String description; + + public GenericHelp(String summary, String description) { + this.summary = summary; + this.description = description; + } + + @Override + public String getSummary() { + return summary; + } + + @Override + public String getDescription() { + return description; + } + + } + + private ICommandHandler handler; + private ICommandHelp help; + + /** + * Create a new generic command + * + * @param handler + * The handler to use for the command + * @param description + * The description of the command + * @param help + * The detailed help message for the command + */ + public GenericCommand(ICommandHandler handler, String description, + String help) { + this.handler = handler; + this.help = new GenericHelp(description, help); + } + + @Override + public ICommandHandler getHandler() { + return handler; + } + + @Override + public ICommandHelp getHelp() { + return help; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java new file mode 100644 index 0000000..681986d --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommand.java @@ -0,0 +1,23 @@ +package bjc.utils.cli; + +/** + * Represents a command that can be invoked from a {@link ICommandMode} + * + * @author ben + * + */ +public interface ICommand { + /** + * Get the handler that executes this command + * + * @return The handler that executes this command + */ + public ICommandHandler getHandler(); + + /** + * Get the help entry for this command + * + * @return The help entry for this command + */ + public ICommandHelp getHelp(); +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java new file mode 100644 index 0000000..ad03dac --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/ICommandHelp.java @@ -0,0 +1,26 @@ +package bjc.utils.cli; + +/** + * Interface for the help entry for a command + * + * @author ben + * + */ +public interface ICommandHelp { + /** + * Get the summary line for a command + * + * Used for 'help commands' which gives the user a brief idea what all + * the commands do + * + * @return The summary line line for a command + */ + public String getSummary(); + + /** + * Get the description of a command + * + * @return The description of a command + */ + public String getDescription(); +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java b/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java index 4aea0d6..37c94f6 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java +++ b/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java @@ -2,14 +2,15 @@ package bjc.utils.components; import java.io.File; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; /** * A component repository that loads its components from files in a @@ -29,7 +30,7 @@ public class FileComponentRepository<E extends IDescribedComponent> /** * The internal storage of components */ - private Map<String, E> components; + private IFunctionalMap<String, E> components; /** * The path that all the components came from @@ -57,7 +58,8 @@ public class FileComponentRepository<E extends IDescribedComponent> + "Components can only be read from a directory"); } - components = new HashMap<>(); + components = new FunctionalMap<>(); + sourceDirectory = directory.toPath().toAbsolutePath(); File[] listFiles = directory.listFiles(); @@ -100,8 +102,8 @@ public class FileComponentRepository<E extends IDescribedComponent> } @Override - public FunctionalList<E> getComponentList() { - FunctionalList<E> returnedList = new FunctionalList<>(); + public IFunctionalList<E> getComponentList() { + IFunctionalList<E> returnedList = new FunctionalList<>(); components .forEach((name, component) -> returnedList.add(component)); @@ -110,7 +112,7 @@ public class FileComponentRepository<E extends IDescribedComponent> } @Override - public Map<String, E> getComponents() { + public IFunctionalMap<String, E> getComponents() { return components; } diff --git a/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java b/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java index 135e609..c720015 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java +++ b/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java @@ -1,8 +1,7 @@ package bjc.utils.components; -import java.util.Map; - -import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; /** * A collection of implementations of {@link IDescribedComponent} @@ -18,7 +17,7 @@ public interface IComponentRepository<E extends IDescribedComponent> { * * @return A list of all the registered components */ - public FunctionalList<E> getComponentList(); + public IFunctionalList<E> getComponentList(); /** * Get all of the components this repository knows about @@ -26,7 +25,7 @@ public interface IComponentRepository<E extends IDescribedComponent> { * @return A map from component name to component, containing all of * the components in the repositories */ - public Map<String, E> getComponents(); + public IFunctionalMap<String, E> getComponents(); /** * Get a component with a specific name diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java b/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java index 97cb195..f721a9a 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java +++ b/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java @@ -92,4 +92,9 @@ public class Pair<L, R> implements IPair<L, R> { return merger.apply(leftValue, rightValue); } + + @Override + public String toString() { + return "pair[l=" + leftValue.toString() + ", r=" + rightValue.toString() + "]"; + } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java index 4b8ed30..2ad8dbf 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java +++ b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java @@ -6,6 +6,7 @@ import java.util.function.Supplier; import bjc.utils.data.IHolder; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; /** * Holds a single value of a specific type. This is used for indirect @@ -22,15 +23,19 @@ import bjc.utils.funcdata.FunctionalList; public class LazyHolder<T> implements IHolder<T>, ILazy { private final class LazyHolderSupplier<NewT> implements Supplier<NewT> { - private FunctionalList<Function<T, T>> pendingActions; + private IFunctionalList<Function<T, T>> pendingActions; private Function<T, NewT> pendingTransform; - public LazyHolderSupplier(FunctionalList<Function<T, T>> actons, + public LazyHolderSupplier(IFunctionalList<Function<T, T>> actons, Function<T, NewT> transform) { // Resolve latent bug I just realized. After a map, adding new // actions to the original holder could've resulted in changes // to all unactualized mapped values from that holder - pendingActions = actons.clone(); + pendingActions = new FunctionalList<>(); + + for (Function<T, T> action : actons.toIterable()) { + pendingActions.add(action); + } this.pendingTransform = transform; } @@ -50,7 +55,7 @@ public class LazyHolder<T> implements IHolder<T>, ILazy { /** * List of queued actions to be performed on realized values */ - private FunctionalList<Function<T, T>> actions = new FunctionalList<>(); + private IFunctionalList<Function<T, T>> actions = new FunctionalList<>(); /** * The value internally held by this lazy holder diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java index c680879..9574376 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java @@ -14,6 +14,7 @@ import java.util.function.Predicate; import bjc.utils.data.GenHolder; import bjc.utils.data.IHolder; +import bjc.utils.data.IPair; import bjc.utils.data.Pair; import java.util.ArrayList; @@ -28,7 +29,7 @@ import java.util.ArrayList; * @param <E> * The type in this list */ -public class FunctionalList<E> implements Cloneable { +public class FunctionalList<E> implements Cloneable, IFunctionalList<E> { /** * The list used as a backing store */ @@ -57,27 +58,6 @@ public class FunctionalList<E> implements Cloneable { } /** - * Create a functional list using the same backing list as the provided - * list. - * - * @param sourceList - * The source for a backing list - */ - public FunctionalList(FunctionalList<E> sourceList) { - if (sourceList == null) { - throw new NullPointerException("Source list must be non-null"); - } - - // Find out if this should make a copy of the source's wrapped list - // instead. - // - // I've decided it shouldn't. Call clone() if that's what you want. - // This method just creates another list that refers to the - // source's backing list - wrappedList = sourceList.wrappedList; - } - - /** * Create a new functional list with the specified size. * * @param size @@ -102,26 +82,18 @@ public class FunctionalList<E> implements Cloneable { wrappedList = backingList; } - /** - * Add an item to this list - * - * @param item - * The item to add to this list. - * @return Whether the item was added to the list succesfully. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#add(E) */ + @Override public boolean add(E item) { return wrappedList.add(item); } - /** - * Check if all of the elements of this list match the specified - * predicate. - * - * @param matchPredicate - * The predicate to use for checking. - * @return Whether all of the elements of the list match the specified - * predicate. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#allMatch(java.util.function.Predicate) */ + @Override public boolean allMatch(Predicate<E> matchPredicate) { if (matchPredicate == null) { throw new NullPointerException("Predicate must be non-null"); @@ -138,14 +110,10 @@ public class FunctionalList<E> implements Cloneable { return true; } - /** - * Check if any of the elements in this list match the specified list. - * - * @param matchPredicate - * The predicate to use for checking. - * @return Whether any element in the list matches the provided - * predicate. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#anyMatch(java.util.function.Predicate) */ + @Override public boolean anyMatch(Predicate<E> matchPredicate) { if (matchPredicate == null) { throw new NullPointerException("Predicate must be not null"); @@ -163,8 +131,8 @@ public class FunctionalList<E> implements Cloneable { } @Override - public FunctionalList<E> clone() { - FunctionalList<E> clonedList = new FunctionalList<>(); + public IFunctionalList<E> clone() { + IFunctionalList<E> clonedList = new FunctionalList<>(); for (E element : wrappedList) { clonedList.add(element); @@ -173,27 +141,12 @@ public class FunctionalList<E> implements Cloneable { return clonedList; } - /** - * Combine this list with another one into a new list and merge the - * results. Works sort of like a combined zip/map over resulting pairs. - * Does not change the underlying list. - * - * NOTE: The returned list will have the length of the shorter of this - * list and the combined one. - * - * @param <T> - * The type of the second list - * @param <F> - * The type of the combined list - * - * @param rightList - * The list to combine with - * @param itemCombiner - * The function to use for combining element pairs. - * @return A new list containing the merged pairs of lists. - */ - public <T, F> FunctionalList<F> combineWith( - FunctionalList<T> rightList, + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#combineWith(bjc.utils.funcdata.IFunctionalList, java.util.function.BiFunction) + */ + @Override + public <T, F> IFunctionalList<F> combineWith( + IFunctionalList<T> rightList, BiFunction<E, T, F> itemCombiner) { if (rightList == null) { throw new NullPointerException( @@ -202,7 +155,7 @@ public class FunctionalList<E> implements Cloneable { throw new NullPointerException("Combiner must not be null"); } - FunctionalList<F> returnedList = new FunctionalList<>(); + IFunctionalList<F> returnedList = new FunctionalList<>(); // Get the iterator for the other list Iterator<T> rightIterator = rightList.toIterable().iterator(); @@ -220,23 +173,19 @@ public class FunctionalList<E> implements Cloneable { return returnedList; } - /** - * Check if the list contains the specified item - * - * @param item - * The item to see if it is contained - * @return Whether or not the specified item is in the list + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#contains(E) */ + @Override public boolean contains(E item) { // Check if any items in the list match the provided item return this.anyMatch(item::equals); } - /** - * Get the first element in the list - * - * @return The first element in this list. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#first() */ + @Override public E first() { if (wrappedList.size() < 1) { throw new NoSuchElementException( @@ -246,29 +195,21 @@ public class FunctionalList<E> implements Cloneable { return wrappedList.get(0); } - /** - * Apply a function to each member of the list, then flatten the - * results. Does not change the underlying list. - * - * @param <T> - * The type of the flattened list - * - * @param elementExpander - * The function to apply to each member of the list. - * @return A new list containing the flattened results of applying the - * provided function. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#flatMap(java.util.function.Function) */ - public <T> FunctionalList<T> flatMap( - Function<E, FunctionalList<T>> elementExpander) { + @Override + public <T> IFunctionalList<T> flatMap( + Function<E, IFunctionalList<T>> elementExpander) { if (elementExpander == null) { throw new NullPointerException("Expander must not be null"); } - FunctionalList<T> returnedList = new FunctionalList<>( + IFunctionalList<T> returnedList = new FunctionalList<>( this.wrappedList.size()); forEach(element -> { - FunctionalList<T> expandedElement = elementExpander + IFunctionalList<T> expandedElement = elementExpander .apply(element); if (expandedElement == null) { @@ -283,12 +224,10 @@ public class FunctionalList<E> implements Cloneable { return returnedList; } - /** - * Apply a given action for each member of the list - * - * @param action - * The action to apply to each member of the list. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#forEach(java.util.function.Consumer) */ + @Override public void forEach(Consumer<E> action) { if (action == null) { throw new NullPointerException("Action is null"); @@ -297,13 +236,10 @@ public class FunctionalList<E> implements Cloneable { wrappedList.forEach(action); } - /** - * Apply a given function to each element in the list and its index. - * - * @param indexedAction - * The function to apply to each element in the list and its - * index. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#forEachIndexed(java.util.function.BiConsumer) */ + @Override public void forEachIndexed(BiConsumer<Integer, E> indexedAction) { if (indexedAction == null) { throw new NullPointerException("Action must not be null"); @@ -322,13 +258,10 @@ public class FunctionalList<E> implements Cloneable { }); } - /** - * Retrieve a value in the list by its index. - * - * @param index - * The index to retrieve a value from. - * @return The value at the specified index in the list. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#getByIndex(int) */ + @Override public E getByIndex(int index) { return wrappedList.get(index); } @@ -342,19 +275,16 @@ public class FunctionalList<E> implements Cloneable { return wrappedList; } - /** - * Retrieve a list containing all elements matching a predicate - * - * @param matchPredicate - * The predicate to match by - * @return A list containing all elements that match the predicate + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#getMatching(java.util.function.Predicate) */ - public FunctionalList<E> getMatching(Predicate<E> matchPredicate) { + @Override + public IFunctionalList<E> getMatching(Predicate<E> matchPredicate) { if (matchPredicate == null) { throw new NullPointerException("Predicate must not be null"); } - FunctionalList<E> returnedList = new FunctionalList<>(); + IFunctionalList<E> returnedList = new FunctionalList<>(); wrappedList.forEach((element) -> { if (matchPredicate.test(element)) { @@ -366,41 +296,32 @@ public class FunctionalList<E> implements Cloneable { return returnedList; } - /** - * Retrieve the size of the wrapped list - * - * @return The size of the wrapped list + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#getSize() */ + @Override public int getSize() { return wrappedList.size(); } - /** - * Check if this list is empty. - * - * @return Whether or not this list is empty. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#isEmpty() */ + @Override public boolean isEmpty() { return wrappedList.isEmpty(); } - /** - * Create a new list by applying the given function to each element in - * the list. Does not change the underlying list. - * - * @param <T> - * The type of the transformed list - * - * @param elementTransformer - * The function to apply to each element in the list - * @return A new list containing the mapped elements of this list. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#map(java.util.function.Function) */ - public <T> FunctionalList<T> map(Function<E, T> elementTransformer) { + @Override + public <T> IFunctionalList<T> map(Function<E, T> elementTransformer) { if (elementTransformer == null) { throw new NullPointerException("Transformer must be not null"); } - FunctionalList<T> returnedList = new FunctionalList<>( + IFunctionalList<T> returnedList = new FunctionalList<>( this.wrappedList.size()); forEach(element -> { @@ -411,30 +332,20 @@ public class FunctionalList<E> implements Cloneable { return returnedList; } - /** - * Zip two lists into a list of pairs - * - * @param <T> - * The type of the second list - * - * @param rightList - * The list to use as the left side of the pair - * @return A list containing pairs of this element and the specified - * list + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#pairWith(bjc.utils.funcdata.IFunctionalList) */ - public <T> FunctionalList<Pair<E, T>> pairWith( - FunctionalList<T> rightList) { + @Override + public <T> IFunctionalList<IPair<E, T>> pairWith( + IFunctionalList<T> rightList) { return combineWith(rightList, Pair<E, T>::new); } - /** - * Partition this list into a list of sublists - * - * @param numberPerPartition - * The size of elements to put into each one of the sublists - * @return A list partitioned into partitions of size nPerPart + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#partition(int) */ - public FunctionalList<FunctionalList<E>> partition( + @Override + public IFunctionalList<IFunctionalList<E>> partition( int numberPerPartition) { if (numberPerPartition < 1 || numberPerPartition > wrappedList.size()) { @@ -443,10 +354,10 @@ public class FunctionalList<E> implements Cloneable { + wrappedList.size()); } - FunctionalList<FunctionalList<E>> returnedList = new FunctionalList<>(); + IFunctionalList<IFunctionalList<E>> returnedList = new FunctionalList<>(); // The current partition being filled - GenHolder<FunctionalList<E>> currentPartition = new GenHolder<>( + GenHolder<IFunctionalList<E>> currentPartition = new GenHolder<>( new FunctionalList<>()); this.forEach((element) -> { @@ -472,29 +383,23 @@ public class FunctionalList<E> implements Cloneable { * Check if a partition has room for another item */ private Boolean isPartitionFull(int numberPerPartition, - GenHolder<FunctionalList<E>> currentPartition) { + GenHolder<IFunctionalList<E>> currentPartition) { return currentPartition.unwrap( (partition) -> partition.getSize() >= numberPerPartition); } - /** - * Prepend an item to the list - * - * @param item - * The item to prepend to the list + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#prepend(E) */ + @Override public void prepend(E item) { wrappedList.add(0, item); } - /** - * Select a random item from this list, using the provided random - * number generator. - * - * @param rnd - * The random number generator to use. - * @return A random element from this list. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#randItem(java.util.Random) */ + @Override public E randItem(Random rnd) { if (rnd == null) { throw new NullPointerException( @@ -506,25 +411,10 @@ public class FunctionalList<E> implements Cloneable { return wrappedList.get(randomIndex); } - /** - * Reduce this list to a single value, using a accumulative approach. - * - * @param <T> - * The in-between type of the values - * @param <F> - * The final value type - * - * @param initialValue - * The initial value of the accumulative state. - * @param stateAccumulator - * The function to use to combine a list element with the - * accumulative state. - * @param resultTransformer - * The function to use to convert the accumulative state - * into a final result. - * @return A single value condensed from this list and transformed into - * its final state. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#reduceAux(T, java.util.function.BiFunction, java.util.function.Function) */ + @Override public <T, F> F reduceAux(T initialValue, BiFunction<E, T, T> stateAccumulator, Function<T, F> resultTransformer) { @@ -547,13 +437,10 @@ public class FunctionalList<E> implements Cloneable { return currentState.unwrap(resultTransformer); } - /** - * Remove all elements that match a given predicate - * - * @param removePredicate - * The predicate to use to determine elements to delete - * @return Whether there was anything that satisfied the predicate + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#removeIf(java.util.function.Predicate) */ + @Override public boolean removeIf(Predicate<E> removePredicate) { if (removePredicate == null) { throw new NullPointerException("Predicate must be non-null"); @@ -562,28 +449,18 @@ public class FunctionalList<E> implements Cloneable { return wrappedList.removeIf(removePredicate); } - /** - * Remove all parameters that match a given parameter - * - * @param desiredElement - * The object to remove all matching copies of + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#removeMatching(E) */ + @Override public void removeMatching(E desiredElement) { removeIf((element) -> element.equals(desiredElement)); } - /** - * Perform a binary search for the specified key using the provided - * means of comparing elements. Since this IS a binary search, the list - * must have been sorted before hand. - * - * @param searchKey - * The key to search for. - * @param comparator - * The way to compare elements for searching. Pass null to - * use the natural ordering for E - * @return The element if it is in this list, or null if it is not. + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#search(E, java.util.Comparator) */ + @Override public E search(E searchKey, Comparator<E> comparator) { // Search our internal list int foundIndex = Collections.binarySearch(wrappedList, searchKey, @@ -598,23 +475,18 @@ public class FunctionalList<E> implements Cloneable { return null; } - /** - * Sort the elements of this list using the provided way of comparing - * elements. Does change the underlying list. - * - * @param comparator - * The way to compare elements for sorting. Pass null to use - * E's natural ordering + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#sort(java.util.Comparator) */ + @Override public void sort(Comparator<E> comparator) { Collections.sort(wrappedList, comparator); } - /** - * Convert the list into a iterable - * - * @return An iterable view onto the list + /* (non-Javadoc) + * @see bjc.utils.funcdata.IFunctionalList#toIterable() */ + @Override public Iterable<E> toIterable() { return wrappedList; } diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java index 0453988..fc4c4de 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java @@ -2,27 +2,40 @@ package bjc.utils.funcdata; import java.util.HashMap; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Function; import bjc.utils.data.Pair; /** - * Functional wrapper over map providing some useful things + * Basic implementation of {@link IFunctionalMap} * * @author ben - * + * * @param <K> - * The type of this map's keys + * The type of the map's keys * @param <V> - * The type of this map's values - * + * The type of the map's values */ -public class FunctionalMap<K, V> { - private final class TransformedMap<V2> extends FunctionalMap<K, V2> { - private FunctionalMap<K, V> mapToTransform; - private Function<V, V2> transformer; +public class FunctionalMap<K, V> implements IFunctionalMap<K, V> { + /** + * A map that transforms values from one type to another + * + * @author ben + * + * @param <K> + * The type of the map's keys + * @param <V> + * The type of the map's values + * @param <V2> + * The type of the transformed values + */ + private static final class TransformedValueMap<K, V, V2> + implements IFunctionalMap<K, V2> { + private IFunctionalMap<K, V> mapToTransform; + private Function<V, V2> transformer; - public TransformedMap(FunctionalMap<K, V> destMap, + public TransformedValueMap(IFunctionalMap<K, V> destMap, Function<V, V2> transform) { mapToTransform = destMap; transformer = transform; @@ -42,6 +55,40 @@ public class FunctionalMap<K, V> { public String toString() { return mapToTransform.toString(); } + + @Override + public V2 put(K key, V2 val) { + throw new UnsupportedOperationException( + "Can't add items to transformed map"); + } + + @Override + public <V3> IFunctionalMap<K, V3> mapValues( + Function<V2, V3> transform) { + return new TransformedValueMap<>(this, transform); + } + + @Override + public IFunctionalList<K> keyList() { + return mapToTransform.keyList(); + } + + @Override + public void forEach(BiConsumer<K, V2> action) { + mapToTransform.forEach((key, val) -> { + action.accept(key, transformer.apply(val)); + }); + } + + @Override + public V2 remove(K key) { + return transformer.apply(mapToTransform.remove(key)); + } + + @Override + public int getSize() { + return mapToTransform.getSize(); + } } private Map<K, V> wrappedMap; @@ -84,18 +131,12 @@ public class FunctionalMap<K, V> { } } - /** - * Add an entry to the map - * - * @param key - * The key to put the value under - * @param val - * The value to add - * @return The previous value of the key in the map, or null if the key - * wasn't in the map. However, note that it may also return - * null if the key was set to null. + /* + * (non-Javadoc) * + * @see bjc.utils.funcdata.IFunctionalMap#put(K, V) */ + @Override public V put(K key, V val) { if (key == null) { throw new NullPointerException("Key must not be null"); @@ -104,15 +145,12 @@ public class FunctionalMap<K, V> { return wrappedMap.put(key, val); } - /** - * Get the value assigned to the given key - * - * @param key - * The key to look for a value under - * @return The value of the key - * + /* + * (non-Javadoc) * + * @see bjc.utils.funcdata.IFunctionalMap#get(K) */ + @Override public V get(K key) { if (key == null) { throw new NullPointerException("Key must not be null"); @@ -126,35 +164,28 @@ public class FunctionalMap<K, V> { return wrappedMap.get(key); } - /** - * Transform the values returned by this map. + /* + * (non-Javadoc) * - * NOTE: This transform is applied once for each lookup of a value, so - * the transform passed should be a proper function, or things will - * likely not work as expected. - * - * @param <V2> - * The new type of returned values - * @param transformer - * The function to use to transform values - * @return The map where each value will be transformed after lookup + * @see bjc.utils.funcdata.IFunctionalMap#mapValues(java.util.function. + * Function) */ - public <V2> FunctionalMap<K, V2> mapValues( + @Override + public <V2> IFunctionalMap<K, V2> mapValues( Function<V, V2> transformer) { if (transformer == null) { throw new NullPointerException("Transformer must not be null"); } - return new TransformedMap<>(this, transformer); + return new TransformedValueMap<>(this, transformer); } - /** - * Check if this map contains the specified key + /* + * (non-Javadoc) * - * @param key - * The key to check - * @return Whether or not the map contains the key + * @see bjc.utils.funcdata.IFunctionalMap#containsKey(K) */ + @Override public boolean containsKey(K key) { return wrappedMap.containsKey(key); } @@ -163,4 +194,30 @@ public class FunctionalMap<K, V> { public String toString() { return wrappedMap.toString(); } + + @Override + public IFunctionalList<K> keyList() { + FunctionalList<K> keys = new FunctionalList<>(); + + wrappedMap.keySet().forEach((key) -> { + keys.add(key); + }); + + return keys; + } + + @Override + public void forEach(BiConsumer<K, V> action) { + wrappedMap.forEach(action); + } + + @Override + public V remove(K key) { + return wrappedMap.remove(key); + } + + @Override + public int getSize() { + return wrappedMap.size(); + } }
\ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java index 9ef59fb..0e2d199 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java @@ -137,13 +137,13 @@ public class FunctionalStringTokenizer { * The function to use to convert tokens. * @return A list containing all of the converted tokens. */ - public <E> FunctionalList<E> toList( + public <E> IFunctionalList<E> toList( Function<String, E> tokenTransformer) { if (tokenTransformer == null) { throw new NullPointerException("Transformer must not be null"); } - FunctionalList<E> returnList = new FunctionalList<>(); + IFunctionalList<E> returnList = new FunctionalList<>(); // Add each token to the list after transforming it forEachToken(token -> { @@ -160,7 +160,7 @@ public class FunctionalStringTokenizer { * * @return This tokenizer, converted into a list of strings */ - public FunctionalList<String> toList() { + public IFunctionalList<String> toList() { return toList((String element) -> element); } diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java new file mode 100644 index 0000000..a017aa9 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java @@ -0,0 +1,281 @@ +package bjc.utils.funcdata; + +import java.util.Comparator; +import java.util.Random; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; + +import bjc.utils.data.IPair; + +/** + * A wrapper over another list that provides eager functional operations + * over it. Differs from a stream in every way except for the fact that + * they both provide functional operations. + * + * @author ben + * + * @param <E> + * The type in this list + */ +public interface IFunctionalList<E> { + + /** + * Add an item to this list + * + * @param item + * The item to add to this list. + * @return Whether the item was added to the list succesfully. + */ + boolean add(E item); + + /** + * Check if all of the elements of this list match the specified + * predicate. + * + * @param matchPredicate + * The predicate to use for checking. + * @return Whether all of the elements of the list match the specified + * predicate. + */ + boolean allMatch(Predicate<E> matchPredicate); + + /** + * Check if any of the elements in this list match the specified list. + * + * @param matchPredicate + * The predicate to use for checking. + * @return Whether any element in the list matches the provided + * predicate. + */ + boolean anyMatch(Predicate<E> matchPredicate); + + /** + * Combine this list with another one into a new list and merge the + * results. Works sort of like a combined zip/map over resulting pairs. + * Does not change the underlying list. + * + * NOTE: The returned list will have the length of the shorter of this + * list and the combined one. + * + * @param <T> + * The type of the second list + * @param <F> + * The type of the combined list + * + * @param rightList + * The list to combine with + * @param itemCombiner + * The function to use for combining element pairs. + * @return A new list containing the merged pairs of lists. + */ + <T, F> IFunctionalList<F> combineWith(IFunctionalList<T> rightList, + BiFunction<E, T, F> itemCombiner); + + /** + * Check if the list contains the specified item + * + * @param item + * The item to see if it is contained + * @return Whether or not the specified item is in the list + */ + boolean contains(E item); + + /** + * Get the first element in the list + * + * @return The first element in this list. + */ + E first(); + + /** + * Apply a function to each member of the list, then flatten the + * results. Does not change the underlying list. + * + * @param <T> + * The type of the flattened list + * + * @param elementExpander + * The function to apply to each member of the list. + * @return A new list containing the flattened results of applying the + * provided function. + */ + <T> IFunctionalList<T> flatMap( + Function<E, IFunctionalList<T>> elementExpander); + + /** + * Apply a given action for each member of the list + * + * @param action + * The action to apply to each member of the list. + */ + void forEach(Consumer<E> action); + + /** + * Apply a given function to each element in the list and its index. + * + * @param indexedAction + * The function to apply to each element in the list and its + * index. + */ + void forEachIndexed(BiConsumer<Integer, E> indexedAction); + + /** + * Retrieve a value in the list by its index. + * + * @param index + * The index to retrieve a value from. + * @return The value at the specified index in the list. + */ + E getByIndex(int index); + + /** + * Retrieve a list containing all elements matching a predicate + * + * @param matchPredicate + * The predicate to match by + * @return A list containing all elements that match the predicate + */ + IFunctionalList<E> getMatching(Predicate<E> matchPredicate); + + /** + * Retrieve the size of the wrapped list + * + * @return The size of the wrapped list + */ + int getSize(); + + /** + * Check if this list is empty. + * + * @return Whether or not this list is empty. + */ + boolean isEmpty(); + + /** + * Create a new list by applying the given function to each element in + * the list. Does not change the underlying list. + * + * @param <T> + * The type of the transformed list + * + * @param elementTransformer + * The function to apply to each element in the list + * @return A new list containing the mapped elements of this list. + */ + <T> IFunctionalList<T> map(Function<E, T> elementTransformer); + + /** + * Zip two lists into a list of pairs + * + * @param <T> + * The type of the second list + * + * @param rightList + * The list to use as the left side of the pair + * @return A list containing pairs of this element and the specified + * list + */ + <T> IFunctionalList<IPair<E, T>> pairWith( + IFunctionalList<T> rightList); + + /** + * Partition this list into a list of sublists + * + * @param numberPerPartition + * The size of elements to put into each one of the sublists + * @return A list partitioned into partitions of size nPerPart + */ + IFunctionalList<IFunctionalList<E>> partition(int numberPerPartition); + + /** + * Prepend an item to the list + * + * @param item + * The item to prepend to the list + */ + void prepend(E item); + + /** + * Select a random item from this list, using the provided random + * number generator. + * + * @param rnd + * The random number generator to use. + * @return A random element from this list. + */ + E randItem(Random rnd); + + /** + * Reduce this list to a single value, using a accumulative approach. + * + * @param <T> + * The in-between type of the values + * @param <F> + * The final value type + * + * @param initialValue + * The initial value of the accumulative state. + * @param stateAccumulator + * The function to use to combine a list element with the + * accumulative state. + * @param resultTransformer + * The function to use to convert the accumulative state + * into a final result. + * @return A single value condensed from this list and transformed into + * its final state. + */ + <T, F> F reduceAux(T initialValue, + BiFunction<E, T, T> stateAccumulator, + Function<T, F> resultTransformer); + + /** + * Remove all elements that match a given predicate + * + * @param removePredicate + * The predicate to use to determine elements to delete + * @return Whether there was anything that satisfied the predicate + */ + boolean removeIf(Predicate<E> removePredicate); + + /** + * Remove all parameters that match a given parameter + * + * @param desiredElement + * The object to remove all matching copies of + */ + void removeMatching(E desiredElement); + + /** + * Perform a binary search for the specified key using the provided + * means of comparing elements. Since this IS a binary search, the list + * must have been sorted before hand. + * + * @param searchKey + * The key to search for. + * @param comparator + * The way to compare elements for searching. Pass null to + * use the natural ordering for E + * @return The element if it is in this list, or null if it is not. + */ + E search(E searchKey, Comparator<E> comparator); + + /** + * Sort the elements of this list using the provided way of comparing + * elements. Does change the underlying list. + * + * @param comparator + * The way to compare elements for sorting. Pass null to use + * E's natural ordering + */ + void sort(Comparator<E> comparator); + + /** + * Convert the list into a iterable + * + * @return An iterable view onto the list + */ + Iterable<E> toIterable(); +}
\ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalMap.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalMap.java new file mode 100644 index 0000000..9bd62bc --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalMap.java @@ -0,0 +1,104 @@ +package bjc.utils.funcdata; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * Functional wrapper over map providing some useful things + * + * @author ben + * + * @param <K> + * The type of this map's keys + * @param <V> + * The type of this map's values + * + */ +public interface IFunctionalMap<K, V> { + + /** + * Add an entry to the map + * + * @param key + * The key to put the value under + * @param val + * The value to add + * @return The previous value of the key in the map, or null if the key + * wasn't in the map. However, note that it may also return + * null if the key was set to null. + * + * @throws UnsupportedOperationException + * if the map implementation doesn't support modifying the + * map + */ + V put(K key, V val); + + /** + * Get the value assigned to the given key + * + * @param key + * The key to look for a value under + * @return The value of the key + * + * + */ + V get(K key); + + /** + * Transform the values returned by this map. + * + * NOTE: This transform is applied once for each lookup of a value, so + * the transform passed should be a proper function, or things will + * likely not work as expected. + * + * @param <V2> + * The new type of returned values + * @param transformer + * The function to use to transform values + * @return The map where each value will be transformed after lookup + */ + <V2> IFunctionalMap<K, V2> mapValues(Function<V, V2> transformer); + + /** + * Check if this map contains the specified key + * + * @param key + * The key to check + * @return Whether or not the map contains the key + */ + boolean containsKey(K key); + + /** + * Get a list of all the keys in this map + * + * @return A list of all the keys in this map + */ + IFunctionalList<K> keyList(); + + /** + * Execute an action for each entry in the map + * + * @param action + * the action to execute for each entry in the map + */ + void forEach(BiConsumer<K, V> action); + + /** + * Remove the value bound to the key + * + * @param key + * The key to remove from the map + * @return The previous value for the key in the map, or null if the + * key wasn't in the class. NOTE: Just because you recieved + * null, doesn't mean the map wasn't changed. It may mean that + * someone put a null value for that key into the map + */ + V remove(K key); + + /** + * Get the number of entries in this map + * + * @return The number of entries in this map + */ + int getSize(); +}
\ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java index fa92f85..67b9985 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.function.Predicate; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod; /** @@ -68,7 +69,7 @@ public class BinarySearchTree<T> { * time, but also O(N) space. */ public void balance() { - FunctionalList<T> elements = new FunctionalList<>(); + IFunctionalList<T> elements = new FunctionalList<>(); // Add each element to the list in sorted order rootElement.forEach(TreeLinearizationMethod.INORDER, @@ -123,7 +124,7 @@ public class BinarySearchTree<T> { * The distance from the pivot * @return Whether the adjusted pivot is with the list */ - private boolean adjustedPivotInBounds(FunctionalList<T> elements, + private boolean adjustedPivotInBounds(IFunctionalList<T> elements, int pivot, int pivotAdjustment) { return (pivot - pivotAdjustment) >= 0 && (pivot + pivotAdjustment) < elements.getSize(); diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/EnumUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/EnumUtils.java new file mode 100644 index 0000000..f490727 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/EnumUtils.java @@ -0,0 +1,64 @@ +package bjc.utils.funcutils; + +import java.util.Random; +import java.util.function.Consumer; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; + +/** + * Utility methods on enums + * + * @author ben + * + */ +public class EnumUtils { + /** + * Get a random value from an enum + * + * @param <E> + * The type of the enum + * @param enumClass + * The class of the enum + * @param rnd + * The random source to use + * @return A random value from the specified enum + */ + public static <E extends Enum<E>> E getRandomValue(Class<E> enumClass, + Random rnd) { + E[] enumValues = enumClass.getEnumConstants(); + + return new FunctionalList<>(enumValues).randItem(rnd); + } + + /** + * Do an action for a random number of enum values + * + * @param <E> + * The type of the enum + * @param enumClass + * The enum class + * @param nValues + * The number of values to execute the action on + * @param action + * The action to perform on random values + * @param rnd + * The source of randomness to use + */ + public static <E extends Enum<E>> void doForValues(Class<E> enumClass, + int nValues, Consumer<E> action, Random rnd) { + E[] enumValues = enumClass.getEnumConstants(); + + IFunctionalList<E> valueList = new FunctionalList<>(enumValues); + + int randomValueCount = enumValues.length - nValues; + + for (int i = 0; i <= randomValueCount; i++) { + E rDir = valueList.randItem(rnd); + + valueList.removeMatching(rDir); + } + + valueList.forEach(action); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java new file mode 100644 index 0000000..fd09fbb --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java @@ -0,0 +1,77 @@ +package bjc.utils.funcutils; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.function.BiPredicate; + +/** + * Utilities for doing things with files + * + * @author ben + * + */ +public class FileUtils { + private static final class FunctionalFileVisitor + extends SimpleFileVisitor<Path> { + private BiPredicate<Path, BasicFileAttributes> traversalPredicate; + private BiPredicate<Path, BasicFileAttributes> traversalAction; + + public FunctionalFileVisitor( + BiPredicate<Path, BasicFileAttributes> traversalPredicate, + BiPredicate<Path, BasicFileAttributes> traversalAction) { + this.traversalPredicate = traversalPredicate; + this.traversalAction = traversalAction; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) throws IOException { + if (traversalPredicate.test(dir, attrs)) { + return FileVisitResult.CONTINUE; + } + + return FileVisitResult.SKIP_SUBTREE; + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + if (traversalAction.test(file, attrs)) { + return FileVisitResult.CONTINUE; + } + + return FileVisitResult.TERMINATE; + } + } + + /** + * Traverse a directory recursively. This is a depth-first traversal + * + * + * @param root + * The directory to start the traversal at + * @param traversalPredicate + * The predicate to determine whether or not to traverse a + * directory + * @param traversalAction + * The action to invoke upon each file in the directory. + * Returning true means to continue the traversal, returning + * false stops it + * @throws IOException + * if the walk throws an exception + * + * TODO If it becomes necessary, write another overload for + * this with all the buttons and knobs from walkFileTree + */ + public static void traverseDirectory(Path root, + BiPredicate<Path, BasicFileAttributes> traversalPredicate, + BiPredicate<Path, BasicFileAttributes> traversalAction) + throws IOException { + Files.walkFileTree(root, new FunctionalFileVisitor( + traversalPredicate, traversalAction)); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/FuncUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FuncUtils.java new file mode 100644 index 0000000..d89b7da --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FuncUtils.java @@ -0,0 +1,44 @@ +package bjc.utils.funcutils; + +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.IntConsumer; + +/** + * Utility things for functions + * + * @author ben + * + */ +public class FuncUtils { + /** + * Do the specified action the specified number of times + * + * @param nTimes + * The number of times to do the action + * @param cons + * The action to perform + */ + public static void doTimes(int nTimes, IntConsumer cons) { + for (int i = 0; i < nTimes; i++) { + cons.accept(i); + } + } + + /** + * Convert a binary function into a unary function that returns a + * function + * + * @param <A> The initial type of the function + * @param <B> The intermediate type of the function + * @param <C> The terminal type of the function + * @param func The function to transform + * @return The function transformed into a unary function returning a function + */ + public static <A, B, C> Function<A, Function<B, C>> curry2( + BiFunction<A, B, C> func) { + return (arg1) -> (arg2) -> { + return func.apply(arg1, arg2); + }; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java index 1d2750b..871e1cf 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java @@ -6,8 +6,9 @@ import java.util.function.Consumer; import java.util.function.Function; import bjc.utils.data.GenHolder; -import bjc.utils.data.Pair; +import bjc.utils.data.IPair; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; /** * Utilities for manipulating FunctionalLists that don't belong in the @@ -20,7 +21,7 @@ public class ListUtils { private static final int MAX_NTRIESPART = 50; private static final class TokenDeaffixer - implements BiFunction<String, String, FunctionalList<String>> { + implements BiFunction<String, String, IFunctionalList<String>> { private String token; public TokenDeaffixer(String tok) { @@ -28,7 +29,7 @@ public class ListUtils { } @Override - public FunctionalList<String> apply(String operatorName, + public IFunctionalList<String> apply(String operatorName, String operatorRegex) { if (operatorName == null) { throw new NullPointerException( @@ -53,7 +54,7 @@ public class ListUtils { } private static final class TokenSplitter - implements BiFunction<String, String, FunctionalList<String>> { + implements BiFunction<String, String, IFunctionalList<String>> { private String tokenToSplit; public TokenSplitter(String tok) { @@ -61,7 +62,7 @@ public class ListUtils { } @Override - public FunctionalList<String> apply(String operatorName, + public IFunctionalList<String> apply(String operatorName, String operatorRegex) { if (operatorName == null) { throw new NullPointerException( @@ -77,10 +78,10 @@ public class ListUtils { return new FunctionalList<>(tokenToSplit); } - FunctionalList<String> splitTokens = new FunctionalList<>( + IFunctionalList<String> splitTokens = new FunctionalList<>( tokenToSplit.split(operatorRegex)); - FunctionalList<String> result = new FunctionalList<>(); + IFunctionalList<String> result = new FunctionalList<>(); int tokenExpansionSize = splitTokens.getSize(); @@ -112,17 +113,17 @@ public class ListUtils { */ private static final class GroupPartIteration<E> implements Consumer<E> { - private FunctionalList<FunctionalList<E>> returnedList; - private GenHolder<FunctionalList<E>> currentPartition; - private FunctionalList<E> rejectedItems; + private IFunctionalList<IFunctionalList<E>> returnedList; + private GenHolder<IFunctionalList<E>> currentPartition; + private IFunctionalList<E> rejectedItems; private GenHolder<Integer> numberInCurrentPartition; private int numberPerPartition; private Function<E, Integer> elementCounter; public GroupPartIteration( - FunctionalList<FunctionalList<E>> returned, - GenHolder<FunctionalList<E>> currPart, - FunctionalList<E> rejects, + IFunctionalList<IFunctionalList<E>> returned, + GenHolder<IFunctionalList<E>> currPart, + IFunctionalList<E> rejects, GenHolder<Integer> numInCurrPart, int nPerPart, Function<E, Integer> eleCount) { this.returnedList = returned; @@ -174,8 +175,8 @@ public class ListUtils { * The number of elements to put in each partition * @return A list partitioned according to the above rules */ - public static <E> FunctionalList<FunctionalList<E>> groupPartition( - FunctionalList<E> input, Function<E, Integer> elementCounter, + public static <E> IFunctionalList<IFunctionalList<E>> groupPartition( + IFunctionalList<E> input, Function<E, Integer> elementCounter, int numberPerPartition) { if (input == null) { throw new NullPointerException("Input list must not be null"); @@ -192,17 +193,17 @@ public class ListUtils { /* * List that holds our results */ - FunctionalList<FunctionalList<E>> returnedList = new FunctionalList<>(); + IFunctionalList<IFunctionalList<E>> returnedList = new FunctionalList<>(); /* * List that holds current partition */ - GenHolder<FunctionalList<E>> currentPartition = new GenHolder<>( + GenHolder<IFunctionalList<E>> currentPartition = new GenHolder<>( new FunctionalList<>()); /* * List that holds elements rejected during current pass */ - FunctionalList<E> rejectedElements = new FunctionalList<>(); + IFunctionalList<E> rejectedElements = new FunctionalList<>(); /* * The effective number of elements in the current partitition @@ -251,9 +252,9 @@ public class ListUtils { * @return A list of tokens split on all the operators * */ - public static FunctionalList<String> splitTokens( - FunctionalList<String> input, - Deque<Pair<String, String>> operators) { + public static IFunctionalList<String> splitTokens( + IFunctionalList<String> input, + Deque<IPair<String, String>> operators) { if (input == null) { throw new NullPointerException("Input must not be null"); } else if (operators == null) { @@ -261,7 +262,7 @@ public class ListUtils { "Set of operators must not be null"); } - GenHolder<FunctionalList<String>> returnedList = new GenHolder<>( + GenHolder<IFunctionalList<String>> returnedList = new GenHolder<>( input); operators.forEach((operator) -> returnedList @@ -282,9 +283,9 @@ public class ListUtils { * @return The tokens that have been deaffixed * */ - public static FunctionalList<String> deAffixTokens( - FunctionalList<String> input, - Deque<Pair<String, String>> operators) { + public static IFunctionalList<String> deAffixTokens( + IFunctionalList<String> input, + Deque<IPair<String, String>> operators) { if (input == null) { throw new NullPointerException("Input must not be null"); } else if (operators == null) { @@ -292,7 +293,7 @@ public class ListUtils { "Set of operators must not be null"); } - GenHolder<FunctionalList<String>> returnedList = new GenHolder<>( + GenHolder<IFunctionalList<String>> returnedList = new GenHolder<>( input); operators.forEach((operator) -> returnedList @@ -311,7 +312,7 @@ public class ListUtils { * The list of tokens to collapse * @return The collapsed string of tokens */ - public static String collapseTokens(FunctionalList<String> input) { + public static String collapseTokens(IFunctionalList<String> input) { if (input == null) { throw new NullPointerException("Input must not be null"); } @@ -329,7 +330,7 @@ public class ListUtils { * The seperator to use for seperating tokens * @return The collapsed string of tokens */ - public static String collapseTokens(FunctionalList<String> input, + public static String collapseTokens(IFunctionalList<String> input, String seperator) { if (input == null) { throw new NullPointerException("Input must not be null"); diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java b/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java index 4f194f3..349d9fa 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java @@ -1,8 +1,7 @@ package bjc.utils.gen; -import java.util.HashMap; - -import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; /** * A weighted grammar where all the rules have a equal chance of occuring. @@ -18,7 +17,7 @@ public class RandomGrammar<E> extends WeightedGrammar<E> { * Create a new random grammar. */ public RandomGrammar() { - rules = new HashMap<>(); + rules = new FunctionalMap<>(); } /** @@ -30,8 +29,8 @@ public class RandomGrammar<E> extends WeightedGrammar<E> { * The cases to add for this rule. */ @SafeVarargs - public final void addCases(E rule, FunctionalList<E>... cases) { - for (FunctionalList<E> currentCase : cases) { + public final void addCases(E rule, IFunctionalList<E>... cases) { + for (IFunctionalList<E> currentCase : cases) { super.addCase(rule, 1, currentCase); } } @@ -45,10 +44,10 @@ public class RandomGrammar<E> extends WeightedGrammar<E> { * The cases to add for this rule. */ @SafeVarargs - public final void makeRule(E rule, FunctionalList<E>... cases) { + public final void makeRule(E rule, IFunctionalList<E>... cases) { super.addRule(rule); - for (FunctionalList<E> currentCase : cases) { + for (IFunctionalList<E> currentCase : cases) { super.addCase(rule, 1, currentCase); } } @@ -61,7 +60,8 @@ public class RandomGrammar<E> extends WeightedGrammar<E> { * @param cases * The cases to add for this rule. */ - public void makeRule(E rule, FunctionalList<FunctionalList<E>> cases) { + public void makeRule(E rule, + IFunctionalList<IFunctionalList<E>> cases) { if (cases == null) { throw new NullPointerException("Cases must not be null"); } diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java index 5d61201..37f31b0 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java @@ -1,13 +1,14 @@ package bjc.utils.gen; -import java.util.Hashtable; -import java.util.Map; import java.util.Random; -import java.util.Set; import java.util.function.Function; +import bjc.utils.data.IPair; import bjc.utils.data.Pair; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; /** * A random grammar, where certain rules will come up more often than @@ -22,29 +23,29 @@ public class WeightedGrammar<E> { /** * The initial rule of the grammar */ - protected String initialRule; + protected String initialRule; /** * The rules currently in this grammar */ - protected Map<E, WeightedRandom<FunctionalList<E>>> rules; + protected IFunctionalMap<E, WeightedRandom<IFunctionalList<E>>> rules; /** * The random number generator used for random numbers */ - private Random rng; + private Random rng; /** * All of the subgrammars of this grammar */ - protected Map<E, WeightedGrammar<E>> subgrammars; + protected IFunctionalMap<E, WeightedGrammar<E>> subgrammars; /** * Create a new weighted grammar. */ public WeightedGrammar() { - rules = new Hashtable<>(); - subgrammars = new Hashtable<>(); + rules = new FunctionalMap<>(); + subgrammars = new FunctionalMap<>(); } /** @@ -76,7 +77,7 @@ public class WeightedGrammar<E> { * The case being added. */ public void addCase(E ruleName, int probability, - FunctionalList<E> cse) { + IFunctionalList<E> cse) { if (ruleName == null) { throw new NullPointerException("Rule name must be not null"); } else if (cse == null) { @@ -145,7 +146,7 @@ public class WeightedGrammar<E> { * @return Whether or not the rule was succesfully added. */ public boolean addRule(E name, - WeightedRandom<FunctionalList<E>> cases) { + WeightedRandom<IFunctionalList<E>> cases) { if (name == null) { throw new NullPointerException("Name must not be null"); } else if (cases == null) { @@ -193,15 +194,15 @@ public class WeightedGrammar<E> { * The rule to test. * @return A set of sentances generated by the specified rule. */ - public FunctionalList<FunctionalList<E>> generateDebugValues( + public IFunctionalList<IFunctionalList<E>> generateDebugValues( E ruleName) { if (ruleName == null) { throw new NullPointerException("Rule name must not be null"); } - FunctionalList<FunctionalList<E>> returnedList = new FunctionalList<>(); + IFunctionalList<IFunctionalList<E>> returnedList = new FunctionalList<>(); - WeightedRandom<FunctionalList<E>> ruleGenerator = rules + WeightedRandom<IFunctionalList<E>> ruleGenerator = rules .get(ruleName); for (int i = 0; i < 10; i++) { @@ -226,7 +227,7 @@ public class WeightedGrammar<E> { * @return A randomly generated sentance from the specified initial * rule. */ - public <T> FunctionalList<T> generateGenericValues(E initRule, + public <T> IFunctionalList<T> generateGenericValues(E initRule, Function<E, T> tokenTransformer, T spacer) { if (initRule == null) { throw new NullPointerException( @@ -237,7 +238,7 @@ public class WeightedGrammar<E> { throw new NullPointerException("Spacer must not be null"); } - FunctionalList<T> returnedList = new FunctionalList<>(); + IFunctionalList<T> returnedList = new FunctionalList<>(); if (subgrammars.containsKey(initRule)) { subgrammars.get(initRule).generateGenericValues(initRule, @@ -280,7 +281,7 @@ public class WeightedGrammar<E> { * @return A list of random grammar elements generated by the specified * rule. */ - public FunctionalList<E> generateListValues(E initRule, E spacer) { + public IFunctionalList<E> generateListValues(E initRule, E spacer) { return generateGenericValues(initRule, strang -> strang, spacer); } @@ -342,16 +343,23 @@ public class WeightedGrammar<E> { "Number of times to prefix must be positive."); } - WeightedRandom<FunctionalList<E>> rule = rules.get(ruleName); + WeightedRandom<IFunctionalList<E>> rule = rules.get(ruleName); - FunctionalList<Pair<Integer, FunctionalList<E>>> newResults = new FunctionalList<>(); + IFunctionalList<IPair<Integer, IFunctionalList<E>>> newResults = new FunctionalList<>(); rule.getValues().forEach((pair) -> { - FunctionalList<FunctionalList<E>> newRule = new FunctionalList<>(); + IFunctionalList<IFunctionalList<E>> newRule = new FunctionalList<>(); for (int i = 1; i <= numberOfTimes; i++) { - FunctionalList<E> newCase = pair - .merge((left, right) -> right.clone()); + IFunctionalList<E> newCase = pair.merge((left, right) -> { + IFunctionalList<E> returnVal = new FunctionalList<>(); + + for (E val : right.toIterable()) { + returnVal.add(val); + } + + return returnVal; + }); for (int j = 1; j <= i; j++) { newCase.prepend(prefixToken); @@ -392,13 +400,21 @@ public class WeightedGrammar<E> { "Prefix token must not be null"); } - WeightedRandom<FunctionalList<E>> rule = rules.get(ruleName); + WeightedRandom<IFunctionalList<E>> rule = rules.get(ruleName); - FunctionalList<Pair<Integer, FunctionalList<E>>> newResults = new FunctionalList<>(); + IFunctionalList<IPair<Integer, IFunctionalList<E>>> newResults = new FunctionalList<>(); rule.getValues().forEach((pair) -> { - FunctionalList<E> newCase = pair - .merge((left, right) -> right.clone()); + IFunctionalList<E> newCase = pair.merge((left, right) -> { + IFunctionalList<E> returnVal = new FunctionalList<>(); + + for (E val : right.toIterable()) { + returnVal.add(val); + } + + return returnVal; + }); + newCase.prepend(prefixToken); newResults.add(new Pair<>(pair.merge((left, right) -> left) @@ -443,7 +459,7 @@ public class WeightedGrammar<E> { * @return The number of rules in this grammar */ public int getRuleCount() { - return rules.size(); + return rules.getSize(); } /** @@ -451,8 +467,8 @@ public class WeightedGrammar<E> { * * @return The set of all rule names in this grammar */ - public Set<E> getRuleNames() { - return rules.keySet(); + public IFunctionalList<E> getRuleNames() { + return rules.keyList(); } /** @@ -484,13 +500,20 @@ public class WeightedGrammar<E> { "Prefix token must not be null"); } - WeightedRandom<FunctionalList<E>> rule = rules.get(ruleName); + WeightedRandom<IFunctionalList<E>> rule = rules.get(ruleName); - FunctionalList<Pair<Integer, FunctionalList<E>>> newResults = new FunctionalList<>(); + IFunctionalList<IPair<Integer, IFunctionalList<E>>> newResults = new FunctionalList<>(); rule.getValues().forEach((par) -> { - FunctionalList<E> newCase = par - .merge((left, right) -> right.clone()); + IFunctionalList<E> newCase = par.merge((left, right) -> { + IFunctionalList<E> returnVal = new FunctionalList<>(); + + for (E val : right.toIterable()) { + returnVal.add(val); + } + + return returnVal; + }); newCase.add(suffixToken); newResults.add(new Pair<>(par.merge((left, right) -> left) diff --git a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java index 5157ee2..10da34e 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java @@ -2,9 +2,10 @@ package bjc.utils.gen; import java.util.Random; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; import bjc.utils.data.GenHolder; import bjc.utils.data.IHolder; -import bjc.utils.data.Pair; +import bjc.utils.data.IPair; /** * Represents a random number generator where certain results are weighted @@ -19,12 +20,12 @@ public class WeightedRandom<E> { /** * The list of probabilities for each result */ - private FunctionalList<Integer> probabilities; + private IFunctionalList<Integer> probabilities; /** * The list of possible results to pick from */ - private FunctionalList<E> results; + private IFunctionalList<E> results; /** * The source for any needed random numbers @@ -101,7 +102,7 @@ public class WeightedRandom<E> { * * @return A list of all the values that can be generated */ - public FunctionalList<E> getResults() { + public IFunctionalList<E> getResults() { return results; } @@ -111,7 +112,7 @@ public class WeightedRandom<E> { * * @return A list of pairs of values and value probabilities */ - public FunctionalList<Pair<Integer, E>> getValues() { + public IFunctionalList<IPair<Integer, E>> getValues() { return probabilities.pairWith(results); } }
\ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java index 247ee31..a6e8eef 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java +++ b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java @@ -3,16 +3,15 @@ package bjc.utils.graph; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; -import java.util.HashMap; -import java.util.HashSet; import java.util.InputMismatchException; -import java.util.Map; -import java.util.Map.Entry; import java.util.Scanner; -import java.util.Set; import java.util.stream.IntStream; import bjc.utils.data.GenHolder; +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; /** * An adjacency map representing a graph @@ -65,7 +64,7 @@ public class AdjacencyMap<T> { "The number of vertices must be greater than 0"); } - Set<Integer> vertices = new HashSet<>(); + IFunctionalList<Integer> vertices = new FunctionalList<>(); IntStream.range(0, numVertices) .forEach(element -> vertices.add(element)); @@ -91,8 +90,9 @@ public class AdjacencyMap<T> { try { columnWeight = Integer.parseInt(part); } catch (NumberFormatException nfex) { - InputMismatchException imex = new InputMismatchException( - "" + part + " is not a valid weight."); + InputMismatchException imex = + new InputMismatchException("" + part + + " is not a valid weight."); imex.initCause(nfex); @@ -119,7 +119,8 @@ public class AdjacencyMap<T> { /** * The backing storage of the map */ - private Map<T, Map<T, Integer>> adjacencyMap = new HashMap<>(); + private IFunctionalMap<T, IFunctionalMap<T, Integer>> adjacencyMap = + new FunctionalMap<>(); /** * Create a new map from a set of vertices @@ -127,13 +128,13 @@ public class AdjacencyMap<T> { * @param vertices * The set of vertices to create a map from */ - public AdjacencyMap(Set<T> vertices) { + public AdjacencyMap(IFunctionalList<T> vertices) { if (vertices == null) { throw new NullPointerException("Vertices must not be null"); } vertices.forEach(vertex -> { - Map<T, Integer> vertexRow = new HashMap<>(); + IFunctionalMap<T, Integer> vertexRow = new FunctionalMap<>(); vertices.forEach( targetVertex -> vertexRow.put(targetVertex, 0)); @@ -150,16 +151,11 @@ public class AdjacencyMap<T> { public boolean isDirected() { GenHolder<Boolean> result = new GenHolder<>(true); - adjacencyMap.entrySet().forEach(mapEntry -> { - Set<Entry<T, Integer>> entryVertices = mapEntry.getValue() - .entrySet(); + adjacencyMap.forEach((key, value) -> { + value.forEach((targetKey, targetValue) -> { + int inverseValue = adjacencyMap.get(targetKey).get(key); - entryVertices.forEach(targetVertex -> { - int leftValue = targetVertex.getValue(); - int rightValue = adjacencyMap.get(targetVertex.getKey()) - .get(mapEntry.getKey()); - - if (leftValue != rightValue) { + if (targetValue != inverseValue) { result.transform((bool) -> false); } }); @@ -206,11 +202,11 @@ public class AdjacencyMap<T> { public Graph<T> toGraph() { Graph<T> returnedGraph = new Graph<>(); - adjacencyMap.entrySet().forEach(sourceVertex -> sourceVertex - .getValue().entrySet() - .forEach(targetVertex -> returnedGraph.addEdge( - sourceVertex.getKey(), targetVertex.getKey(), - targetVertex.getValue()))); + adjacencyMap.forEach((key, value) -> { + value.forEach((targetKey, targetValue) -> { + returnedGraph.addEdge(key, targetKey, targetValue, true); + }); + }); return returnedGraph; } @@ -229,10 +225,11 @@ public class AdjacencyMap<T> { PrintStream outputPrinter = new PrintStream(outputSink); - adjacencyMap.entrySet().forEach(sourceVertex -> { - sourceVertex.getValue().entrySet() - .forEach(targetVertex -> outputPrinter.printf("%d ", - targetVertex.getValue())); + adjacencyMap.forEach((key, value) -> { + value.forEach((targetKey, targetValue) -> { + outputPrinter.printf("%d", targetValue); + }); + outputPrinter.println(); }); diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java b/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java index f6bfc85..8041604 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java +++ b/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java @@ -1,11 +1,8 @@ package bjc.utils.graph; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.NoSuchElementException; import java.util.PriorityQueue; import java.util.Queue; @@ -15,6 +12,9 @@ import java.util.function.BiPredicate; import bjc.utils.data.GenHolder; import bjc.utils.data.IHolder; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; /** * A directed weighted graph, where the vertices have some arbitrary label @@ -29,13 +29,13 @@ public class Graph<T> { /** * The backing representation of the graph */ - private final Map<T, Map<T, Integer>> backingGraph; + private final IFunctionalMap<T, IFunctionalMap<T, Integer>> backingGraph; /** * Create a new graph */ public Graph() { - backingGraph = new HashMap<>(); + backingGraph = new FunctionalMap<>(); } /** @@ -47,8 +47,11 @@ public class Graph<T> { * The target vertex for this edge * @param distance * The distance from the source vertex to the target vertex + * @param directed + * Whether or not */ - public void addEdge(T sourceVertex, T targetVertex, int distance) { + public void addEdge(T sourceVertex, T targetVertex, int distance, + boolean directed) { // Can't add edges with a null source or target if (sourceVertex == null) { throw new NullPointerException( @@ -60,17 +63,22 @@ public class Graph<T> { // Initialize adjacency list for vertices if necessary if (!backingGraph.containsKey(sourceVertex)) { - backingGraph.put(sourceVertex, new HashMap<T, Integer>()); - } - if (!backingGraph.containsKey(targetVertex)) { - backingGraph.put(targetVertex, new HashMap<T, Integer>()); + backingGraph.put(sourceVertex, + new FunctionalMap<T, Integer>()); } // Add the edge to the graph backingGraph.get(sourceVertex).put(targetVertex, distance); - // Uncomment this to make the graph undirected - // graph.get(target).put(source, distance); + // Handle possible directed edges + if (!directed) { + if (!backingGraph.containsKey(targetVertex)) { + backingGraph.put(targetVertex, + new FunctionalMap<T, Integer>()); + } + + backingGraph.get(targetVertex).put(sourceVertex, distance); + } } /** @@ -107,7 +115,7 @@ public class Graph<T> { * The vertex to use as a source * @return All of the edges with the specified vertex as a source */ - public Map<T, Integer> getEdges(T source) { + public IFunctionalMap<T, Integer> getEdges(T source) { // Can't find edges for a null source if (source == null) { throw new NullPointerException("The source cannot be null."); @@ -116,7 +124,7 @@ public class Graph<T> { "Vertex " + source + " is not in graph"); } - return Collections.unmodifiableMap(backingGraph.get(source)); + return backingGraph.get(source); } /** @@ -125,7 +133,7 @@ public class Graph<T> { * @return The initial vertex of the graph */ public T getInitial() { - return backingGraph.keySet().iterator().next(); + return backingGraph.keyList().first(); } /** @@ -195,7 +203,7 @@ public class Graph<T> { * @return A count of the vertices in this graph */ public int getVertexCount() { - return backingGraph.size(); + return backingGraph.getSize(); } /** @@ -203,8 +211,8 @@ public class Graph<T> { * * @return A unmodifiable set of all the vertices in the graph. */ - public Set<T> getVertices() { - return Collections.unmodifiableSet(backingGraph.keySet()); + public IFunctionalList<T> getVertices() { + return backingGraph.keyList(); } /** @@ -249,13 +257,13 @@ public class Graph<T> { */ public AdjacencyMap<T> toAdjacencyMap() { AdjacencyMap<T> adjacencyMap = - new AdjacencyMap<>(backingGraph.keySet()); + new AdjacencyMap<>(backingGraph.keyList()); - backingGraph.entrySet().forEach(sourceVertex -> sourceVertex - .getValue() - .forEach((targetVertex, vertexWeight) -> adjacencyMap - .setWeight(sourceVertex.getKey(), targetVertex, - vertexWeight))); + backingGraph.forEach((key, value) -> { + value.forEach((targetKey, targetValue) -> { + adjacencyMap.setWeight(key, targetKey, targetValue); + }); + }); return adjacencyMap; } @@ -274,7 +282,7 @@ public class Graph<T> { Graph<E> g = new Graph<>(); edges.forEach(edge -> g.addEdge(edge.getSource(), edge.getTarget(), - edge.getDistance())); + edge.getDistance(), true)); return g; } diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java b/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java index e563530..766b241 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java @@ -2,10 +2,10 @@ package bjc.utils.gui; import java.io.File; import javax.swing.filechooser.FileFilter; -import java.util.ArrayList; import java.util.List; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; /** * A file filter based on extensions. @@ -19,7 +19,7 @@ public class ExtensionFileFilter extends FileFilter { /** * The list holding all filtered extensions */ - private FunctionalList<String> extensions; + private IFunctionalList<String> extensions; /** * Create a new filter only showing files with the specified @@ -40,11 +40,7 @@ public class ExtensionFileFilter extends FileFilter { * The extensions to show in this filter. */ public ExtensionFileFilter(String... exts) { - extensions = new FunctionalList<>(new ArrayList<>(exts.length)); - - for (String extension : exts) { - extensions.add(extension); - } + extensions = new FunctionalList<>(exts); } @Override diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java b/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java index 4bbe6e7..26a5a78 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java @@ -9,7 +9,7 @@ import javax.swing.JList; import javax.swing.JPanel; import javax.swing.ListSelectionModel; -import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; import bjc.utils.gui.layout.HLayout; import bjc.utils.gui.layout.VLayout; @@ -54,7 +54,7 @@ public class ListParameterPanel<E> extends JPanel { */ public ListParameterPanel(Supplier<E> addAction, Consumer<E> editAction, Consumer<E> removeAction, - FunctionalList<E> defaultValues) { + IFunctionalList<E> defaultValues) { setLayout(new VLayout(2)); JList<E> list; diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java index 7e2c2d2..230b768 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java @@ -2,10 +2,10 @@ package bjc.utils.gui.awt; import java.io.File; import java.io.FilenameFilter; -import java.util.ArrayList; import java.util.List; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; /** * Filter a set of filenames by extension. @@ -19,7 +19,7 @@ public class ExtensionFileFilter implements FilenameFilter { /** * The list of extensions to filter */ - private FunctionalList<String> extensions; + private IFunctionalList<String> extensions; /** * Create a new filter only showing files with the specified @@ -44,11 +44,7 @@ public class ExtensionFileFilter implements FilenameFilter { * The extensions to show in this filter. */ public ExtensionFileFilter(String... exts) { - extensions = new FunctionalList<>(new ArrayList<>(exts.length)); - - for (String extension : exts) { - extensions.add(extension); - } + extensions = new FunctionalList<>(exts); } @Override diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java index 90961d5..88b4862 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java @@ -183,11 +183,14 @@ public class AST<T> { /** * Expand the nodes in an AST * + * This is actually equivalent to converting the tree into an ordered + * list, doing a flatMap, and then reconstructing the tree + * * @param expander * The function to use for expanding nodes * @return The expanded AST */ - public AST<T> expand(Function<T, AST<T>> expander) { + public AST<T> flatMapTree(Function<T, AST<T>> expander) { if (expander == null) { throw new NullPointerException("Expander must not be null"); } diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java index b6162e5..999503c 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java @@ -8,6 +8,7 @@ import java.util.Scanner; import java.util.function.BiConsumer; import java.util.function.Consumer; +import bjc.utils.data.IPair; import bjc.utils.data.Pair; import bjc.utils.exceptions.UnknownPragmaException; import bjc.utils.funcdata.FunctionalStringTokenizer; @@ -20,9 +21,10 @@ import bjc.utils.funcdata.FunctionalStringTokenizer; * * @param <E> * The type of the state object to use + * */ public class RuleBasedConfigReader<E> { - private BiConsumer<FunctionalStringTokenizer, Pair<String, E>> startRule; + private BiConsumer<FunctionalStringTokenizer, IPair<String, E>> startRule; private BiConsumer<FunctionalStringTokenizer, E> continueRule; private Consumer<E> endRule; @@ -39,7 +41,7 @@ public class RuleBasedConfigReader<E> { * The action to fire when ending a rule */ public RuleBasedConfigReader( - BiConsumer<FunctionalStringTokenizer, Pair<String, E>> startRule, + BiConsumer<FunctionalStringTokenizer, IPair<String, E>> startRule, BiConsumer<FunctionalStringTokenizer, E> continueRule, Consumer<E> endRule) { this.startRule = startRule; @@ -90,20 +92,26 @@ public class RuleBasedConfigReader<E> { state = initialState; boolean ruleOpen = false; + while (inputSource.hasNextLine()) { String line = inputSource.nextLine(); - if (line.equals("")) { + if (line.startsWith("#") || line.startsWith("//")) { + // It's a comment + continue; + } else if (line.equals("")) { if (ruleOpen == false) { // Ignore blank line without an open rule - } - - if (endRule == null) { - // Nothing happens on rule end } else { - endRule.accept(state); - } + if (endRule == null) { + // Nothing happens on rule end + ruleOpen = false; + } else { + endRule.accept(state); + } + ruleOpen = false; + } continue; } else if (line.startsWith("\t")) { if (ruleOpen == false) { @@ -125,9 +133,7 @@ public class RuleBasedConfigReader<E> { String nextToken = tokenizer.nextToken(); - if (nextToken.equals("#") || nextToken.equals("//")) { - // Do nothing, this is a comment - } else if (nextToken.equals("pragma")) { + if (nextToken.equals("pragma")) { String token = tokenizer.nextToken(); pragmas.getOrDefault(token, (tokenzer, stat) -> { @@ -181,7 +187,7 @@ public class RuleBasedConfigReader<E> { * The action to execute on starting of a rule */ public void setStartRule( - BiConsumer<FunctionalStringTokenizer, Pair<String, E>> startRule) { + BiConsumer<FunctionalStringTokenizer, IPair<String, E>> startRule) { if (startRule == null) { throw new NullPointerException( "Action on rule start must be non-null"); diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java index 1e5d487..a60cb01 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java @@ -1,13 +1,14 @@ package bjc.utils.parserutils; import java.util.Deque; -import java.util.HashMap; import java.util.LinkedList; -import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.FunctionalMap; +import bjc.utils.funcdata.IFunctionalList; +import bjc.utils.funcdata.IFunctionalMap; import bjc.utils.funcutils.StringUtils; /** @@ -61,11 +62,11 @@ public class ShuntingYard<E> { } private final class TokenShunter implements Consumer<String> { - private FunctionalList<E> output; + private IFunctionalList<E> output; private Deque<String> stack; private Function<String, E> transform; - public TokenShunter(FunctionalList<E> outpt, Deque<String> stack, + public TokenShunter(IFunctionalList<E> outpt, Deque<String> stack, Function<String, E> transform) { this.output = outpt; this.stack = stack; @@ -115,13 +116,13 @@ public class ShuntingYard<E> { /** * Holds all the shuntable operations */ - private Map<String, IPrecedent> operators; + private IFunctionalMap<String, IPrecedent> operators; /** * Create a new shunting yard with a default set of operators */ public ShuntingYard() { - operators = new HashMap<>(); + operators = new FunctionalMap<>(); if (shouldConfigureBasicOperators) { operators.put("+", Operator.ADD); @@ -175,7 +176,7 @@ public class ShuntingYard<E> { * The function to use to transform strings to tokens * @return A list of tokens in postfix notation */ - public FunctionalList<E> postfix(FunctionalList<String> input, + public IFunctionalList<E> postfix(IFunctionalList<String> input, Function<String, E> tokenTransformer) { if (input == null) { throw new NullPointerException("Input must not be null"); @@ -183,7 +184,7 @@ public class ShuntingYard<E> { throw new NullPointerException("Transformer must not be null"); } - FunctionalList<E> output = new FunctionalList<>(); + IFunctionalList<E> output = new FunctionalList<>(); Deque<String> stack = new LinkedList<>(); diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java index 6fedf87..46e4da4 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java @@ -9,7 +9,7 @@ import java.util.function.Predicate; import bjc.utils.data.GenHolder; import bjc.utils.data.IPair; import bjc.utils.data.Pair; -import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; /** * Creates a parse tree from a postfix expression @@ -119,7 +119,7 @@ public class TreeConstructor { * operator * @return A AST from the expression */ - public static <T> AST<T> constructTree(FunctionalList<T> tokens, + public static <T> AST<T> constructTree(IFunctionalList<T> tokens, Predicate<T> operatorPredicate) { return constructTree(tokens, operatorPredicate, (op) -> false, null); @@ -149,7 +149,7 @@ public class TreeConstructor { * interface. Maybe there's a better way to express how that * works */ - public static <T> AST<T> constructTree(FunctionalList<T> tokens, + public static <T> AST<T> constructTree(IFunctionalList<T> tokens, Predicate<T> operatorPredicate, Predicate<T> isSpecialOperator, Function<Deque<AST<T>>, AST<T>> handleSpecialOperator) { if (tokens == null) { |
