From 77fcc58d1facffbc3af50be8c05985350e9f1355 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Sun, 17 Apr 2016 15:01:44 -0400 Subject: Code maintenace and changes --- .../main/java/bjc/utils/cli/DelegatingCommand.java | 29 ++ .../main/java/bjc/utils/cli/GenericCommand.java | 28 -- .../java/bjc/utils/cli/GenericCommandMode.java | 136 +++++---- .../components/ComponentDescriptionFileParser.java | 59 ++-- .../utils/components/FileComponentRepository.java | 90 +++--- .../src/main/java/bjc/utils/data/BoundLazy.java | 99 +++++++ .../main/java/bjc/utils/data/BoundLazyPair.java | 104 +++++++ .../java/bjc/utils/data/HalfBoundLazyPair.java | 93 ++++++ .../src/main/java/bjc/utils/data/IHolder.java | 101 +++++++ BJC-Utils2/src/main/java/bjc/utils/data/IPair.java | 97 +++++++ .../src/main/java/bjc/utils/data/Identity.java | 115 ++++++++ BJC-Utils2/src/main/java/bjc/utils/data/Lazy.java | 136 +++++++++ .../src/main/java/bjc/utils/data/LazyPair.java | 134 +++++++++ BJC-Utils2/src/main/java/bjc/utils/data/Pair.java | 63 ++++ .../java/bjc/utils/data/experimental/IHolder.java | 101 ------- .../java/bjc/utils/data/experimental/IPair.java | 97 ------- .../java/bjc/utils/data/experimental/Identity.java | 115 -------- .../java/bjc/utils/data/experimental/Lazy.java | 228 --------------- .../java/bjc/utils/data/experimental/LazyPair.java | 317 --------------------- .../java/bjc/utils/data/experimental/Pair.java | 63 ---- .../bjc/utils/data/experimental/package-info.java | 7 - .../src/main/java/bjc/utils/data/package-info.java | 7 + .../main/java/bjc/utils/funcdata/ExtendedMap.java | 96 +++++++ .../java/bjc/utils/funcdata/FunctionalList.java | 13 +- .../java/bjc/utils/funcdata/FunctionalMap.java | 138 ++------- .../java/bjc/utils/funcdata/IFunctionalList.java | 8 +- .../java/bjc/utils/funcdata/IFunctionalMap.java | 11 +- .../bjc/utils/funcdata/TransformedValueMap.java | 100 +++++++ .../src/main/java/bjc/utils/funcdata/Tree.java | 46 ++- .../main/java/bjc/utils/funcutils/FileUtils.java | 35 --- .../bjc/utils/funcutils/FunctionalFileVisitor.java | 41 +++ .../bjc/utils/funcutils/GroupPartIteration.java | 64 +++++ .../main/java/bjc/utils/funcutils/ListUtils.java | 198 +++---------- .../main/java/bjc/utils/funcutils/StringUtils.java | 14 + .../java/bjc/utils/funcutils/TokenDeaffixer.java | 39 +++ .../java/bjc/utils/funcutils/TokenSplitter.java | 56 ++++ .../src/main/java/bjc/utils/gen/RandomGrammar.java | 1 - .../main/java/bjc/utils/gen/WeightedGrammar.java | 4 +- .../main/java/bjc/utils/gen/WeightedRandom.java | 6 +- .../main/java/bjc/utils/graph/AdjacencyMap.java | 74 ++--- .../src/main/java/bjc/utils/graph/Graph.java | 36 +-- .../java/bjc/utils/gui/ListParameterPanel.java | 23 +- .../utils/parserutils/RuleBasedConfigReader.java | 116 ++++---- .../java/bjc/utils/parserutils/ShuntingYard.java | 13 +- .../bjc/utils/parserutils/TokenTransformer.java | 94 ++++++ .../bjc/utils/parserutils/TreeConstructor.java | 99 +------ 46 files changed, 1926 insertions(+), 1618 deletions(-) create mode 100644 BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/BoundLazy.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/BoundLazyPair.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/HalfBoundLazyPair.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/IHolder.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/IPair.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/Identity.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/Lazy.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/LazyPair.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/Pair.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java delete mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/data/package-info.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcdata/ExtendedMap.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcdata/TransformedValueMap.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcutils/FunctionalFileVisitor.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcutils/GroupPartIteration.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenDeaffixer.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenSplitter.java create mode 100644 BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenTransformer.java diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java new file mode 100644 index 0000000..76794cf --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/DelegatingCommand.java @@ -0,0 +1,29 @@ +package bjc.utils.cli; + +class DelegatingCommand implements ICommand { + private ICommand delegate; + + public DelegatingCommand(ICommand delegate) { + this.delegate = delegate; + } + + @Override + public ICommandHandler getHandler() { + return delegate.getHandler(); + } + + @Override + public ICommandHelp getHelp() { + return delegate.getHelp(); + } + + @Override + public ICommand createAlias() { + return new DelegatingCommand(delegate); + } + + @Override + public boolean isAlias() { + return true; + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java index 658a299..3c0aef6 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommand.java @@ -7,34 +7,6 @@ package bjc.utils.cli; * */ public class GenericCommand implements ICommand { - private static class DelegatingCommand implements ICommand { - private ICommand delegate; - - public DelegatingCommand(ICommand delegate) { - this.delegate = delegate; - } - - @Override - public ICommandHandler getHandler() { - return delegate.getHandler(); - } - - @Override - public ICommandHelp getHelp() { - return delegate.getHelp(); - } - - @Override - public ICommand createAlias() { - return new DelegatingCommand(delegate); - } - - @Override - public boolean isAlias() { - return true; - } - } - private ICommandHandler handler; private ICommandHelp help; diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java index c52bb08..84b4d39 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java +++ b/BJC-Utils2/src/main/java/bjc/utils/cli/GenericCommandMode.java @@ -49,64 +49,7 @@ public class GenericCommandMode implements ICommandMode { defaultHandlers = new FunctionalMap<>(new TreeMap<>()); helpTopics = new FunctionalMap<>(new TreeMap<>()); - setupDefaultCommands(errorOutput); - } - - private void setupDefaultCommands(Consumer errorOutput) { - 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", 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) -> { - if (args == null || args.length == 0) { - // Invoke general help - helpSummary(); - } else { - // Invoke help for a command - helpCommand(args[0]); - } - - 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")); - - addCommandAlias("help", "man"); - - // Add commands handled in a upper layer - defaultHandlers.put("clear", new GenericCommand((args) -> { - errorOutput.accept( - "ERROR: This console doesn't support screen clearing"); - - return this; - }, "clear\tClear the screen", - "clear clears the screen of all the text on it," - + " and prepares a fresh prompt.")); - - defaultHandlers.put("exit", new GenericCommand((args) -> { - errorOutput.accept( - "ERROR: This console doesn't support auto-exiting"); - - return this; - }, "exit\tExit the game", - "exit first prompts the user to make sure they want to exit," - + " and if they affirm it, it quits")); + setupDefaultCommands(); } /** @@ -197,6 +140,68 @@ public class GenericCommandMode implements ICommandMode { } } + private GenericCommand buildAliasCommand() { + return 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."); + } + + private GenericCommand buildClearCommands() { + return new GenericCommand((args) -> { + errorOutput.accept( + "ERROR: This console doesn't support screen clearing"); + + return this; + }, "clear\tClear the screen", + "clear clears the screen of all the text on it," + + " and prepares a fresh prompt."); + } + + private GenericCommand buildExitCommand() { + return new GenericCommand((args) -> { + errorOutput.accept( + "ERROR: This console doesn't support auto-exiting"); + + return this; + }, "exit\tExit the game", + "exit first prompts the user to make sure they want to exit," + + " and if they affirm it, it quits"); + } + + private GenericCommand buildHelpCommand() { + return new GenericCommand((args) -> { + if (args == null || args.length == 0) { + // Invoke general help + helpSummary(); + } else { + // Invoke help for a command + helpCommand(args[0]); + } + + 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"); + } + + private GenericCommand buildListCommand() { + return 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."); + } + @Override public boolean canHandleCommand(String command) { return commandHandlers.containsKey(command) @@ -359,6 +364,21 @@ public class GenericCommandMode implements ICommandMode { unknownCommandHandler = handler; } + private void setupDefaultCommands() { + defaultHandlers.put("list", buildListCommand()); + + defaultHandlers.put("alias", buildAliasCommand()); + + defaultHandlers.put("help", buildHelpCommand()); + + addCommandAlias("help", "man"); + + // Add commands handled in a upper layer + defaultHandlers.put("clear", buildClearCommands()); + + defaultHandlers.put("exit", buildExitCommand()); + } + @Override public boolean useCustomPrompt() { return customPrompt != null; diff --git a/BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java b/BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java index 254e380..eec3fa8 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java +++ b/BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java @@ -1,8 +1,10 @@ package bjc.utils.components; import java.io.InputStream; +import java.util.function.BiConsumer; import bjc.utils.exceptions.PragmaFormatException; +import bjc.utils.funcdata.FunctionalStringTokenizer; import bjc.utils.funcutils.ListUtils; import bjc.utils.parserutils.RuleBasedConfigReader; @@ -26,40 +28,21 @@ public class ComponentDescriptionFileParser { // Don't need to do anything on rule end }); - reader.addPragma("name", (tokenizer, state) -> { - if (!tokenizer.hasMoreTokens()) { - throw new PragmaFormatException( - "Pragma name requires one string argument"); - } - - state.setName(ListUtils - .collapseTokens(tokenizer.toList((strang) -> strang))); - }); - - reader.addPragma("author", (tokenizer, state) -> { - if (!tokenizer.hasMoreTokens()) { - throw new PragmaFormatException( - "Pragma author requires one string argument"); - } + setupReaderPragmas(); + } - state.setAuthor(ListUtils - .collapseTokens(tokenizer.toList((strang) -> strang))); - }); + private static void setupReaderPragmas() { + reader.addPragma("name", buildStringCollapserPragma("name")); - reader.addPragma("description", (tokenizer, state) -> { - if (!tokenizer.hasMoreTokens()) { - throw new PragmaFormatException( - "Pragma description requires one string argument"); - } + reader.addPragma("author", buildStringCollapserPragma("author")); - state.setDescription(ListUtils - .collapseTokens(tokenizer.toList((strang) -> strang))); - }); + reader.addPragma("description", + buildStringCollapserPragma("description")); reader.addPragma("version", (tokenizer, state) -> { if (!tokenizer.hasMoreTokens()) { throw new PragmaFormatException( - "Pragma name requires one integer argument"); + "Pragma version requires one integer argument"); } String token = tokenizer.nextToken(); @@ -67,8 +50,8 @@ public class ComponentDescriptionFileParser { try { state.setVersion(Integer.parseInt(token)); } catch (NumberFormatException nfex) { - PragmaFormatException pfex = new PragmaFormatException( - "Argument " + token + PragmaFormatException pfex = + new PragmaFormatException("Argument " + token + " to version pragma isn't a valid integer. " + "This pragma requires a integer argument"); @@ -79,6 +62,20 @@ public class ComponentDescriptionFileParser { }); } + private static + BiConsumer + buildStringCollapserPragma(String pragmaName) { + return (tokenizer, state) -> { + if (!tokenizer.hasMoreTokens()) { + throw new PragmaFormatException("Pragma " + pragmaName + + " requires one string argument"); + } + + state.setName(ListUtils + .collapseTokens(tokenizer.toList((strang) -> strang))); + }; + } + /** * Parse a component description from a stream * @@ -86,8 +83,8 @@ public class ComponentDescriptionFileParser { * The stream to parse from * @return The description parsed from the stream */ - public static ComponentDescription fromStream( - InputStream inputSource) { + public static ComponentDescription + fromStream(InputStream inputSource) { ComponentDescriptionState readState = reader .fromStream(inputSource, new ComponentDescriptionState()); 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 39a7eed..53219fb 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java +++ b/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java @@ -3,13 +3,15 @@ package bjc.utils.components; import java.io.File; import java.io.IOException; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.function.BiPredicate; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.Identity; +import bjc.utils.data.IHolder; +import bjc.utils.data.Identity; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.FunctionalMap; import bjc.utils.funcdata.IFunctionalList; @@ -28,8 +30,8 @@ import bjc.utils.funcutils.FileUtils; public class FileComponentRepository implements IComponentRepository { - private static final Logger CLASS_LOGGER = LoggerFactory - .getLogger(FileComponentRepository.class); + private static final Logger CLASS_LOGGER = + LoggerFactory.getLogger(FileComponentRepository.class); /** * The internal storage of components @@ -68,49 +70,57 @@ public class FileComponentRepository IHolder isFirstDir = new Identity<>(true); - try { - FileUtils.traverseDirectory(sourceDirectory, (pth, attr) -> { - if (attr.isDirectory() && !isFirstDir.getValue()) { - // Don't skip the first directory, that's the parent - isFirstDir.replace(false); - // Skip directories, they probably have component - return false; - } - - return true; - }, (pth, attr) -> { - try { - E component = componentReader.apply(pth.toFile()); - - if (component == null) { - throw new NullPointerException( - "Component reader read null component"); - } else if (!components - .containsKey(component.getName())) { - components.put(component.getName(), component); - } else { - CLASS_LOGGER.warn("Found a duplicate component.\n" - + "Multiple versions of the same component are not currently supported.\n" - + "The component" + component - + " will not be registered ."); + BiPredicate firstLevelTraverser = + (pth, attr) -> { + if (attr.isDirectory() && !isFirstDir.getValue()) { + // Don't skip the first directory, that's the + // parent + isFirstDir.replace(false); + // Skip directories, they probably have + // component + return false; } - } catch (Exception ex) { - CLASS_LOGGER.warn( - "Error found reading component from file " - + pth.toString() - + ". This component will not be loaded", - ex); - } - - // Keep loading components, even if this one failed - return true; - }); + + return true; + }; + + try { + FileUtils.traverseDirectory(sourceDirectory, + firstLevelTraverser, (pth, attr) -> { + loadComponent(componentReader, pth); + + // Keep loading components, even if this one failed + return true; + }); } catch (IOException ioex) { CLASS_LOGGER.warn("Error found reading component from file.", ioex); } } + private void loadComponent(Function componentReader, + Path pth) { + try { + E component = componentReader.apply(pth.toFile()); + + if (component == null) { + throw new NullPointerException( + "Component reader read null component"); + } else if (!components.containsKey(component.getName())) { + components.put(component.getName(), component); + } else { + CLASS_LOGGER.warn("Found a duplicate component.\n" + + "Multiple versions of the same component are not currently supported.\n" + + "The component" + component + + " will not be registered ."); + } + } catch (Exception ex) { + CLASS_LOGGER.warn("Error found reading component from file " + + pth.toString() + + ". This component will not be loaded", ex); + } + } + @Override public IFunctionalList getComponentList() { IFunctionalList returnedList = new FunctionalList<>(); diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazy.java b/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazy.java new file mode 100644 index 0000000..dda65a7 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazy.java @@ -0,0 +1,99 @@ +package bjc.utils.data; + +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; + +class BoundLazy + implements IHolder { + private Supplier> oldSupplier; + + private Function> binder; + + private IHolder boundHolder; + + private boolean holderBound; + + private IFunctionalList> actions = new FunctionalList<>(); + + public BoundLazy(Supplier> supp, + Function> binder) { + oldSupplier = supp; + this.binder = binder; + } + + @Override + public IHolder bind( + Function> bindr) { + IFunctionalList> pendingActions = new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + Supplier> typeSupplier = () -> { + IHolder oldHolder = boundHolder; + + if (!holderBound) { + oldHolder = oldSupplier.get().unwrap(binder); + } + + return pendingActions.reduceAux(oldHolder, (action, state) -> { + return state.transform(action); + }, (value) -> value); + }; + + return new BoundLazy<>(typeSupplier, bindr); + } + + @Override + public IHolder map( + Function mapper) { + IFunctionalList> pendingActions = new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + Supplier typeSupplier = () -> { + IHolder oldHolder = boundHolder; + + if (!holderBound) { + oldHolder = oldSupplier.get().unwrap(binder); + } + + return pendingActions.reduceAux(oldHolder.getValue(), + (action, state) -> { + return action.apply(state); + }, (value) -> mapper.apply(value)); + }; + + return new Lazy<>(typeSupplier); + } + + @Override + public IHolder transform( + UnaryOperator transformer) { + actions.add(transformer); + + return this; + } + + @Override + public UnwrappedType unwrap( + Function unwrapper) { + if (!holderBound) { + boundHolder = oldSupplier.get().unwrap(binder::apply); + } + + return boundHolder.unwrap(unwrapper); + } + + @Override + public String toString() { + if (holderBound) { + return boundHolder.toString(); + } + + return "(unmaterialized)"; + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazyPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazyPair.java new file mode 100644 index 0000000..41ab99b --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/BoundLazyPair.java @@ -0,0 +1,104 @@ +package bjc.utils.data; + +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +class BoundLazyPair + implements IPair { + private Supplier leftSupplier; + private Supplier rightSupplier; + + private BiFunction> binder; + + private IPair boundPair; + + private boolean pairBound; + + public BoundLazyPair(Supplier leftSupp, + Supplier rightSupp, + BiFunction> bindr) { + leftSupplier = leftSupp; + rightSupplier = rightSupp; + binder = bindr; + } + + @Override + public IPair bindLeft( + Function> leftBinder) { + Supplier leftSupp = () -> { + IPair newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(leftSupplier.get(), + rightSupplier.get()); + } + + return newPair.getLeft(); + }; + + return new HalfBoundLazyPair<>(leftSupp, leftBinder); + } + + @Override + public IPair bindRight( + Function> rightBinder) { + Supplier rightSupp = () -> { + IPair newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(leftSupplier.get(), + rightSupplier.get()); + } + + return newPair.getRight(); + }; + + return new HalfBoundLazyPair<>(rightSupp, rightBinder); + } + + @Override + public IPair bind( + BiFunction> bindr) { + IHolder> newPair = new Identity<>( + boundPair); + IHolder newPairMade = new Identity<>(pairBound); + + Supplier leftSupp = () -> { + if (!newPairMade.getValue()) { + newPair.replace(binder.apply(leftSupplier.get(), + rightSupplier.get())); + + newPairMade.replace(false); + } + + return newPair.unwrap((pair) -> pair.getLeft()); + }; + + Supplier rightSupp = () -> { + if (!newPairMade.getValue()) { + newPair.replace(binder.apply(leftSupplier.get(), + rightSupplier.get())); + + newPairMade.replace(false); + } + + return newPair.unwrap((pair) -> pair.getRight()); + }; + + return new BoundLazyPair<>(leftSupp, rightSupp, bindr); + } + + @Override + public MergedType merge( + BiFunction merger) { + if (!pairBound) { + boundPair = binder.apply(leftSupplier.get(), + rightSupplier.get()); + + pairBound = true; + } + + return boundPair.merge(merger); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/HalfBoundLazyPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/HalfBoundLazyPair.java new file mode 100644 index 0000000..f32f58f --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/HalfBoundLazyPair.java @@ -0,0 +1,93 @@ +package bjc.utils.data; + +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +class HalfBoundLazyPair + implements IPair { + private Supplier oldSupplier; + + private Function> binder; + + private IPair boundPair; + private boolean pairBound; + + public HalfBoundLazyPair(Supplier oldSupp, + Function> bindr) { + oldSupplier = oldSupp; + binder = bindr; + } + + @Override + public IPair bindLeft( + Function> leftBinder) { + Supplier leftSupp = () -> { + IPair newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(oldSupplier.get()); + } + + return newPair.getLeft(); + }; + + return new HalfBoundLazyPair<>(leftSupp, leftBinder); + } + + @Override + public IPair bindRight( + Function> rightBinder) { + Supplier rightSupp = () -> { + IPair newPair = boundPair; + + if (!pairBound) { + newPair = binder.apply(oldSupplier.get()); + } + + return newPair.getRight(); + }; + + return new HalfBoundLazyPair<>(rightSupp, rightBinder); + } + + @Override + public IPair bind( + BiFunction> bindr) { + IHolder> newPair = new Identity<>( + boundPair); + IHolder newPairMade = new Identity<>(pairBound); + + Supplier leftSupp = () -> { + if (!newPairMade.getValue()) { + newPair.replace(binder.apply(oldSupplier.get())); + newPairMade.replace(true); + } + + return newPair.unwrap((pair) -> pair.getLeft()); + }; + + Supplier rightSupp = () -> { + if (!newPairMade.getValue()) { + newPair.replace(binder.apply(oldSupplier.get())); + newPairMade.replace(true); + } + + return newPair.unwrap((pair) -> pair.getRight()); + }; + + return new BoundLazyPair<>(leftSupp, rightSupp, bindr); + } + + @Override + public MergedType merge( + BiFunction merger) { + if (!pairBound) { + boundPair = binder.apply(oldSupplier.get()); + + pairBound = true; + } + + return boundPair.merge(merger); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/IHolder.java b/BJC-Utils2/src/main/java/bjc/utils/data/IHolder.java new file mode 100644 index 0000000..77eb899 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/IHolder.java @@ -0,0 +1,101 @@ +package bjc.utils.data; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.UnaryOperator; + +/** + * A holder of a single value. + * + * @author ben + * + * @param + * The type of value held + */ +public interface IHolder { + /** + * Bind a function across the value in this container + * + * @param + * The type of value in this container + * @param binder + * The function to bind to the value + * @return A holder from binding the value + */ + public IHolder bind( + Function> binder); + + /** + * Apply an action to the value + * + * @param action + * The action to apply to the value + */ + public default void doWith(Consumer action) { + transform((value) -> { + action.accept(value); + + return value; + }); + } + + /** + * Get the value contained in this holder without changing it. + * + * @return The value held in this holder + */ + public default ContainedType getValue() { + return unwrap((value) -> value); + } + + /** + * Create a new holder with a mapped version of the value in this + * holder. + * + * Does not change the internal state of this holder + * + * @param + * The type of the mapped value + * @param mapper + * The function to do mapping with + * @return A holder with the mapped value + */ + public IHolder map( + Function mapper); + + /** + * Transform the value held in this holder + * + * @param transformer + * The function to transform the value with + * @return The holder itself, for easy chaining + */ + public IHolder transform( + UnaryOperator transformer); + + /** + * Unwrap the value contained in this holder so that it is no longer + * held + * + * @param + * The type of the unwrapped value + * @param unwrapper + * The function to use to unwrap the value + * @return The unwrapped held value + */ + public UnwrappedType unwrap( + Function unwrapper); + + /** + * Replace the held value with a new one + * + * @param newValue + * The value to hold instead + * @return The holder itself + */ + public default IHolder replace(ContainedType newValue) { + return transform((oldValue) -> { + return newValue; + }); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/IPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/IPair.java new file mode 100644 index 0000000..3d4998c --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/IPair.java @@ -0,0 +1,97 @@ +package bjc.utils.data; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Represents a pair of values + * + * @author ben + * @param + * The type of the left side of the pair + * @param + * The type of the right side of the pair + * + */ +public interface IPair { + /** + * Bind a function to the left value in this pair + * + * @param + * The type of the bound value + * @param leftBinder + * The function to use to bind + * @return A pair with the left type bound + */ + public IPair bindLeft( + Function> leftBinder); + + /** + * Bind a function to the right value in this pair + * + * @param + * The type of the bound value + * @param rightBinder + * The function to use to bind + * @return A pair with the right type bound + */ + public IPair bindRight( + Function> rightBinder); + + /** + * Bind a function across the values in this pair + * + * @param + * The type of the bound left + * @param + * The type of the bound right + * @param binder + * The function to bind with + * @return The bound pair + */ + public IPair bind( + BiFunction> binder); + + /** + * Merge the two values in this pair into a single value + * + * @param + * The type of the single value + * @param merger + * The function to use for merging + * @return The pair, merged into a single value + */ + public MergedType merge( + BiFunction merger); + + /** + * Get the value on the left side of the pair + * + * @return The value on the left side of the pair + */ + public default LeftType getLeft() { + return merge((leftValue, rightValue) -> leftValue); + } + + /** + * Get the value on the right side of the pair + * + * @return The value on the right side of the pair + */ + public default RightType getRight() { + return merge((leftValue, rightValue) -> rightValue); + } + + /** + * Immediately perfom the specified action with the contents of this pair + * @param consumer The action to perform on the pair + */ + public default void doWith(BiConsumer consumer) { + merge((leftValue, rightValue) -> { + consumer.accept(leftValue, rightValue); + + return null; + }); + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/Identity.java b/BJC-Utils2/src/main/java/bjc/utils/data/Identity.java new file mode 100644 index 0000000..dcc7bef --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/Identity.java @@ -0,0 +1,115 @@ +package bjc.utils.data; + +import java.util.function.Function; +import java.util.function.UnaryOperator; + +/** + * @author ben + * + * @param + */ +/** + * Simple implementation of IHolder that has no hidden behavior + * + * @author ben + * + * @param + * The type contained in the holder + */ +public class Identity implements IHolder { + private ContainedType heldValue; + + /** + * Create a holder holding null + */ + public Identity() { + heldValue = null; + } + + /** + * Create a holder holding the specified value + * + * @param value + * The value to hold + */ + public Identity(ContainedType value) { + heldValue = value; + } + + @Override + public IHolder bind( + Function> binder) { + return binder.apply(heldValue); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } else if (getClass() != obj.getClass()) { + return false; + } + + Identity other = (Identity) obj; + + if (heldValue == null) { + if (other.heldValue != null) { + return false; + } + } else if (!heldValue.equals(other.heldValue)) { + return false; + } + + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + + int result = 1; + + int fieldHash = (heldValue == null) ? 0 : heldValue.hashCode(); + + result = prime * result + fieldHash; + + return result; + } + + @Override + public IHolder map( + Function mapper) { + return new Identity<>(mapper.apply(heldValue)); + } + + @Override + public String toString() { + return "holding[v=" + heldValue + "]"; + } + + @Override + public IHolder transform( + UnaryOperator transformer) { + heldValue = transformer.apply(heldValue); + + return this; + } + + @Override + public UnwrappedType unwrap( + Function unwrapper) { + return unwrapper.apply(heldValue); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/Lazy.java b/BJC-Utils2/src/main/java/bjc/utils/data/Lazy.java new file mode 100644 index 0000000..f4bc24a --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/Lazy.java @@ -0,0 +1,136 @@ +package bjc.utils.data; + +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; + +/** + * A holder that holds a means to create a value, but doesn't actually + * compute the value until it's needed + * + * @author ben + * + * @param + */ +public class Lazy implements IHolder { + private Supplier valueSupplier; + + private IFunctionalList> actions = new FunctionalList<>(); + + private boolean valueMaterialized; + + private ContainedType heldValue; + + /** + * Create a new lazy value from the specified seed value + * + * @param value + * The seed value to use + */ + public Lazy(ContainedType value) { + heldValue = value; + + valueMaterialized = true; + } + + /** + * Create a new lazy value from the specified value source + * + * @param supp + * The source of a value to use + */ + public Lazy(Supplier supp) { + valueSupplier = supp; + + valueMaterialized = false; + } + + private Lazy(Supplier supp, + IFunctionalList> pendingActions) { + valueSupplier = supp; + + actions = pendingActions; + } + + @Override + public IHolder bind( + Function> binder) { + IFunctionalList> pendingActions = new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + Supplier supplier = () -> { + if (valueMaterialized) { + return heldValue; + } + + return valueSupplier.get(); + }; + + return new BoundLazy<>(() -> { + return new Lazy<>(supplier, pendingActions); + }, binder); + } + + @Override + public IHolder map( + Function mapper) { + IFunctionalList> pendingActions = new FunctionalList<>(); + + actions.forEach(pendingActions::add); + + return new Lazy<>(() -> { + ContainedType currVal = heldValue; + + if (!valueMaterialized) { + currVal = valueSupplier.get(); + } + + return pendingActions.reduceAux(currVal, + UnaryOperator::apply, + (value) -> mapper.apply(value)); + }); + } + + @Override + public IHolder transform( + UnaryOperator transformer) { + actions.add(transformer); + + return this; + } + + @Override + public UnwrappedType unwrap( + Function unwrapper) { + if (!valueMaterialized) { + heldValue = valueSupplier.get(); + + valueMaterialized = true; + } + + actions.forEach((action) -> { + heldValue = action.apply(heldValue); + }); + + actions = new FunctionalList<>(); + + return unwrapper.apply(heldValue); + } + + @Override + public String toString() { + if (valueMaterialized) { + if (actions.isEmpty()) { + return "value[v='" + heldValue + "']"; + } + + return "value[v='" + heldValue + "'] (has pending transforms)"; + } + + return "(unmaterialized)"; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/LazyPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/LazyPair.java new file mode 100644 index 0000000..fd432c1 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/LazyPair.java @@ -0,0 +1,134 @@ +package bjc.utils.data; + +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * A lazy implementation of a pair + * + * @author ben + * + * @param + * The type on the left side of the pair + * @param + * The type on the right side of the pair + */ +public class LazyPair + implements IPair { + private LeftType leftValue; + private RightType rightValue; + + private Supplier leftSupplier; + private Supplier rightSupplier; + + private boolean leftMaterialized; + private boolean rightMaterialized; + + /** + * Create a new lazy pair, using the set value s + * + * @param leftVal + * The value for the left side of the pair + * @param rightVal + * The value for the right side of the pair + */ + public LazyPair(LeftType leftVal, RightType rightVal) { + leftValue = leftVal; + rightValue = rightVal; + + leftMaterialized = true; + rightMaterialized = true; + } + + /** + * Create a new lazy pair from the given value sources + * + * @param leftSupp + * The source for a value on the left side of the pair + * @param rightSupp + * The source for a value on the right side of the pair + */ + public LazyPair(Supplier leftSupp, + Supplier rightSupp) { + leftSupplier = leftSupp; + rightSupplier = rightSupp; + + leftMaterialized = false; + rightMaterialized = false; + } + + @Override + public IPair bindLeft( + Function> leftBinder) { + Supplier leftSupp = () -> { + if (leftMaterialized) { + return leftValue; + } + + return leftSupplier.get(); + }; + + return new HalfBoundLazyPair<>(leftSupp, leftBinder); + } + + @Override + public IPair bindRight( + Function> rightBinder) { + Supplier rightSupp = () -> { + if (rightMaterialized) { + return rightValue; + } + + return rightSupplier.get(); + }; + + return new HalfBoundLazyPair<>(rightSupp, rightBinder); + } + + @Override + public IPair bind( + BiFunction> binder) { + return new BoundLazyPair<>(leftSupplier, rightSupplier, binder); + } + + @Override + public MergedType merge( + BiFunction merger) { + if (!leftMaterialized) { + leftValue = leftSupplier.get(); + + leftMaterialized = true; + } + + if (!rightMaterialized) { + rightValue = rightSupplier.get(); + + rightMaterialized = true; + } + + return merger.apply(leftValue, rightValue); + } + + @Override + public LeftType getLeft() { + if (!leftMaterialized) { + leftValue = leftSupplier.get(); + + leftMaterialized = true; + } + + return leftValue; + } + + @Override + public RightType getRight() { + if (!rightMaterialized) { + rightValue = rightSupplier.get(); + + rightMaterialized = true; + } + + return rightValue; + } +} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java b/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java new file mode 100644 index 0000000..958df40 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java @@ -0,0 +1,63 @@ +package bjc.utils.data; + +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * A pair of values, with nothing special about them. + * + * @author ben + * + * @param + * The type of the left value + * @param + * The type of the right value + */ +public class Pair + implements IPair { + private LeftType leftValue; + private RightType rightValue; + + /** + * Create a new pair with both sides set to null + */ + public Pair() { + } + + /** + * Create a new pair with both sides set to the specified values + * + * @param left + * The value of the left side + * @param right + * The value of the right side + */ + public Pair(LeftType left, RightType right) { + leftValue = left; + rightValue = right; + } + + @Override + public IPair bindLeft( + Function> leftBinder) { + return leftBinder.apply(leftValue); + } + + @Override + public IPair bindRight( + Function> rightBinder) { + return rightBinder.apply(rightValue); + } + + @Override + public IPair bind( + BiFunction> binder) { + return binder.apply(leftValue, rightValue); + } + + @Override + public MergedType merge( + BiFunction merger) { + return merger.apply(leftValue, rightValue); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java deleted file mode 100644 index 6ccf115..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IHolder.java +++ /dev/null @@ -1,101 +0,0 @@ -package bjc.utils.data.experimental; - -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.UnaryOperator; - -/** - * A holder of a single value. - * - * @author ben - * - * @param - * The type of value held - */ -public interface IHolder { - /** - * Bind a function across the value in this container - * - * @param - * The type of value in this container - * @param binder - * The function to bind to the value - * @return A holder from binding the value - */ - public IHolder bind( - Function> binder); - - /** - * Apply an action to the value - * - * @param action - * The action to apply to the value - */ - public default void doWith(Consumer action) { - transform((value) -> { - action.accept(value); - - return value; - }); - } - - /** - * Get the value contained in this holder without changing it. - * - * @return The value held in this holder - */ - public default ContainedType getValue() { - return unwrap((value) -> value); - } - - /** - * Create a new holder with a mapped version of the value in this - * holder. - * - * Does not change the internal state of this holder - * - * @param - * The type of the mapped value - * @param mapper - * The function to do mapping with - * @return A holder with the mapped value - */ - public IHolder map( - Function mapper); - - /** - * Transform the value held in this holder - * - * @param transformer - * The function to transform the value with - * @return The holder itself, for easy chaining - */ - public IHolder transform( - UnaryOperator transformer); - - /** - * Unwrap the value contained in this holder so that it is no longer - * held - * - * @param - * The type of the unwrapped value - * @param unwrapper - * The function to use to unwrap the value - * @return The unwrapped held value - */ - public UnwrappedType unwrap( - Function unwrapper); - - /** - * Replace the held value with a new one - * - * @param newValue - * The value to hold instead - * @return The holder itself - */ - public default IHolder replace(ContainedType newValue) { - return transform((oldValue) -> { - return newValue; - }); - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java deleted file mode 100644 index f5ca240..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/IPair.java +++ /dev/null @@ -1,97 +0,0 @@ -package bjc.utils.data.experimental; - -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * Represents a pair of values - * - * @author ben - * @param - * The type of the left side of the pair - * @param - * The type of the right side of the pair - * - */ -public interface IPair { - /** - * Bind a function to the left value in this pair - * - * @param - * The type of the bound value - * @param leftBinder - * The function to use to bind - * @return A pair with the left type bound - */ - public IPair bindLeft( - Function> leftBinder); - - /** - * Bind a function to the right value in this pair - * - * @param - * The type of the bound value - * @param rightBinder - * The function to use to bind - * @return A pair with the right type bound - */ - public IPair bindRight( - Function> rightBinder); - - /** - * Bind a function across the values in this pair - * - * @param - * The type of the bound left - * @param - * The type of the bound right - * @param binder - * The function to bind with - * @return The bound pair - */ - public IPair bind( - BiFunction> binder); - - /** - * Merge the two values in this pair into a single value - * - * @param - * The type of the single value - * @param merger - * The function to use for merging - * @return The pair, merged into a single value - */ - public MergedType merge( - BiFunction merger); - - /** - * Get the value on the left side of the pair - * - * @return The value on the left side of the pair - */ - public default LeftType getLeft() { - return merge((leftValue, rightValue) -> leftValue); - } - - /** - * Get the value on the right side of the pair - * - * @return The value on the right side of the pair - */ - public default RightType getRight() { - return merge((leftValue, rightValue) -> rightValue); - } - - /** - * Immediately perfom the specified action with the contents of this pair - * @param consumer The action to perform on the pair - */ - public default void doWith(BiConsumer consumer) { - merge((leftValue, rightValue) -> { - consumer.accept(leftValue, rightValue); - - return null; - }); - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java deleted file mode 100644 index 1780f2d..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Identity.java +++ /dev/null @@ -1,115 +0,0 @@ -package bjc.utils.data.experimental; - -import java.util.function.Function; -import java.util.function.UnaryOperator; - -/** - * @author ben - * - * @param - */ -/** - * Simple implementation of IHolder that has no hidden behavior - * - * @author ben - * - * @param - * The type contained in the holder - */ -public class Identity implements IHolder { - private ContainedType heldValue; - - /** - * Create a holder holding null - */ - public Identity() { - heldValue = null; - } - - /** - * Create a holder holding the specified value - * - * @param value - * The value to hold - */ - public Identity(ContainedType value) { - heldValue = value; - } - - @Override - public IHolder bind( - Function> binder) { - return binder.apply(heldValue); - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else if (obj == null) { - return false; - } else if (getClass() != obj.getClass()) { - return false; - } - - Identity other = (Identity) obj; - - if (heldValue == null) { - if (other.heldValue != null) { - return false; - } - } else if (!heldValue.equals(other.heldValue)) { - return false; - } - - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - - int result = 1; - - int fieldHash = (heldValue == null) ? 0 : heldValue.hashCode(); - - result = prime * result + fieldHash; - - return result; - } - - @Override - public IHolder map( - Function mapper) { - return new Identity<>(mapper.apply(heldValue)); - } - - @Override - public String toString() { - return "holding[v=" + heldValue + "]"; - } - - @Override - public IHolder transform( - UnaryOperator transformer) { - heldValue = transformer.apply(heldValue); - - return this; - } - - @Override - public UnwrappedType unwrap( - Function unwrapper) { - return unwrapper.apply(heldValue); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java deleted file mode 100644 index 0d6fcef..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Lazy.java +++ /dev/null @@ -1,228 +0,0 @@ -package bjc.utils.data.experimental; - -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.function.UnaryOperator; - -import bjc.utils.funcdata.FunctionalList; -import bjc.utils.funcdata.IFunctionalList; - -/** - * A holder that holds a means to create a value, but doesn't actually - * compute the value until it's needed - * - * @author ben - * - * @param - */ -public class Lazy implements IHolder { - private static class BoundLazy - implements IHolder { - private Supplier> oldSupplier; - - private Function> binder; - - private IHolder boundHolder; - - private boolean holderBound; - - private IFunctionalList> actions = new FunctionalList<>(); - - public BoundLazy(Supplier> supp, - Function> binder) { - oldSupplier = supp; - this.binder = binder; - } - - @Override - public IHolder bind( - Function> bindr) { - IFunctionalList> pendingActions = new FunctionalList<>(); - - actions.forEach(pendingActions::add); - - Supplier> typeSupplier = () -> { - IHolder oldHolder = boundHolder; - - if (!holderBound) { - oldHolder = oldSupplier.get().unwrap(binder); - } - - return pendingActions.reduceAux(oldHolder, - (action, state) -> { - return state.transform(action); - }, (value) -> value); - }; - - return new BoundLazy<>(typeSupplier, bindr); - } - - @Override - public IHolder map( - Function mapper) { - IFunctionalList> pendingActions = new FunctionalList<>(); - - actions.forEach(pendingActions::add); - - Supplier typeSupplier = () -> { - IHolder oldHolder = boundHolder; - - if (!holderBound) { - oldHolder = oldSupplier.get().unwrap(binder); - } - - return pendingActions.reduceAux(oldHolder.getValue(), - (action, state) -> { - return action.apply(state); - }, (value) -> mapper.apply(value)); - }; - - return new Lazy<>(typeSupplier); - } - - @Override - public IHolder transform( - UnaryOperator transformer) { - actions.add(transformer); - - return this; - } - - @Override - public UnwrappedType unwrap( - Function unwrapper) { - if (!holderBound) { - boundHolder = oldSupplier.get().unwrap(binder::apply); - } - - return boundHolder.unwrap(unwrapper); - } - - @Override - public String toString() { - if (holderBound) { - return boundHolder.toString(); - } - - return "(unmaterialized)"; - } - } - - private Supplier valueSupplier; - - private IFunctionalList> actions = new FunctionalList<>(); - - private boolean valueMaterialized; - - private ContainedType heldValue; - - /** - * Create a new lazy value from the specified seed value - * - * @param value - * The seed value to use - */ - public Lazy(ContainedType value) { - heldValue = value; - - valueMaterialized = true; - } - - /** - * Create a new lazy value from the specified value source - * - * @param supp - * The source of a value to use - */ - public Lazy(Supplier supp) { - valueSupplier = supp; - - valueMaterialized = false; - } - - private Lazy(Supplier supp, - IFunctionalList> pendingActions) { - valueSupplier = supp; - - actions = pendingActions; - } - - @Override - public IHolder bind( - Function> binder) { - IFunctionalList> pendingActions = new FunctionalList<>(); - - actions.forEach(pendingActions::add); - - Supplier supplier = () -> { - if (valueMaterialized) { - return heldValue; - } - - return valueSupplier.get(); - }; - - return new BoundLazy<>(() -> { - return new Lazy<>(supplier, pendingActions); - }, binder); - } - - @Override - public IHolder map( - Function mapper) { - IFunctionalList> pendingActions = new FunctionalList<>(); - - actions.forEach(pendingActions::add); - - return new Lazy<>(() -> { - ContainedType currVal = heldValue; - - if (!valueMaterialized) { - currVal = valueSupplier.get(); - } - - return pendingActions.reduceAux(currVal, - UnaryOperator::apply, - (value) -> mapper.apply(value)); - }); - } - - @Override - public IHolder transform( - UnaryOperator transformer) { - actions.add(transformer); - - return this; - } - - @Override - public UnwrappedType unwrap( - Function unwrapper) { - if (!valueMaterialized) { - heldValue = valueSupplier.get(); - - valueMaterialized = true; - } - - actions.forEach((action) -> { - heldValue = action.apply(heldValue); - }); - - actions = new FunctionalList<>(); - - return unwrapper.apply(heldValue); - } - - @Override - public String toString() { - if (valueMaterialized) { - if (actions.isEmpty()) { - return "value[v='" + heldValue + "']"; - } - - return "value[v='" + heldValue + "'] (has pending transforms)"; - } - - return "(unmaterialized)"; - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java deleted file mode 100644 index 04a4b61..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/LazyPair.java +++ /dev/null @@ -1,317 +0,0 @@ -package bjc.utils.data.experimental; - -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * A lazy implementation of a pair - * - * @author ben - * - * @param - * The type on the left side of the pair - * @param - * The type on the right side of the pair - */ -public class LazyPair - implements IPair { - private static class HalfBoundLazyPair - implements IPair { - private Supplier oldSupplier; - - private Function> binder; - - private IPair boundPair; - private boolean pairBound; - - public HalfBoundLazyPair(Supplier oldSupp, - Function> bindr) { - oldSupplier = oldSupp; - binder = bindr; - } - - @Override - public IPair bindLeft( - Function> leftBinder) { - Supplier leftSupp = () -> { - IPair newPair = boundPair; - - if (!pairBound) { - newPair = binder.apply(oldSupplier.get()); - } - - return newPair.getLeft(); - }; - - return new HalfBoundLazyPair<>(leftSupp, leftBinder); - } - - @Override - public IPair bindRight( - Function> rightBinder) { - Supplier rightSupp = () -> { - IPair newPair = boundPair; - - if (!pairBound) { - newPair = binder.apply(oldSupplier.get()); - } - - return newPair.getRight(); - }; - - return new HalfBoundLazyPair<>(rightSupp, rightBinder); - } - - @Override - public IPair bind( - BiFunction> bindr) { - IHolder> newPair = new Identity<>( - boundPair); - IHolder newPairMade = new Identity<>(pairBound); - - Supplier leftSupp = () -> { - if (!newPairMade.getValue()) { - newPair.replace(binder.apply(oldSupplier.get())); - newPairMade.replace(true); - } - - return newPair.unwrap((pair) -> pair.getLeft()); - }; - - Supplier rightSupp = () -> { - if (!newPairMade.getValue()) { - newPair.replace(binder.apply(oldSupplier.get())); - newPairMade.replace(true); - } - - return newPair.unwrap((pair) -> pair.getRight()); - }; - - return new BoundLazyPair<>(leftSupp, rightSupp, bindr); - } - - @Override - public MergedType merge( - BiFunction merger) { - if (!pairBound) { - boundPair = binder.apply(oldSupplier.get()); - - pairBound = true; - } - - return boundPair.merge(merger); - } - } - - private static class BoundLazyPair - implements IPair { - private Supplier leftSupplier; - private Supplier rightSupplier; - - private BiFunction> binder; - - private IPair boundPair; - - private boolean pairBound; - - public BoundLazyPair(Supplier leftSupp, - Supplier rightSupp, - BiFunction> bindr) { - leftSupplier = leftSupp; - rightSupplier = rightSupp; - binder = bindr; - } - - @Override - public IPair bindLeft( - Function> leftBinder) { - Supplier leftSupp = () -> { - IPair newPair = boundPair; - - if (!pairBound) { - newPair = binder.apply(leftSupplier.get(), - rightSupplier.get()); - } - - return newPair.getLeft(); - }; - - return new HalfBoundLazyPair<>(leftSupp, leftBinder); - } - - @Override - public IPair bindRight( - Function> rightBinder) { - Supplier rightSupp = () -> { - IPair newPair = boundPair; - - if (!pairBound) { - newPair = binder.apply(leftSupplier.get(), - rightSupplier.get()); - } - - return newPair.getRight(); - }; - - return new HalfBoundLazyPair<>(rightSupp, rightBinder); - } - - @Override - public IPair bind( - BiFunction> bindr) { - IHolder> newPair = new Identity<>( - boundPair); - IHolder newPairMade = new Identity<>(pairBound); - - return new BoundLazyPair<>(() -> { - if (!newPairMade.getValue()) { - newPair.replace(binder.apply(leftSupplier.get(), - rightSupplier.get())); - - newPairMade.replace(false); - } - - return newPair.unwrap((pair) -> pair.getLeft()); - }, () -> { - if (!newPairMade.getValue()) { - newPair.replace(binder.apply(leftSupplier.get(), - rightSupplier.get())); - - newPairMade.replace(false); - } - - return newPair.unwrap((pair) -> pair.getRight()); - }, bindr); - } - - @Override - public MergedType merge( - BiFunction merger) { - if (!pairBound) { - boundPair = binder.apply(leftSupplier.get(), - rightSupplier.get()); - - pairBound = true; - } - - return boundPair.merge(merger); - } - } - - private LeftType leftValue; - private RightType rightValue; - - private Supplier leftSupplier; - private Supplier rightSupplier; - - private boolean leftMaterialized; - private boolean rightMaterialized; - - /** - * Create a new lazy pair, using the set value s - * - * @param leftVal - * The value for the left side of the pair - * @param rightVal - * The value for the right side of the pair - */ - public LazyPair(LeftType leftVal, RightType rightVal) { - leftValue = leftVal; - rightValue = rightVal; - - leftMaterialized = true; - rightMaterialized = true; - } - - /** - * Create a new lazy pair from the given value sources - * - * @param leftSupp - * The source for a value on the left side of the pair - * @param rightSupp - * The source for a value on the right side of the pair - */ - public LazyPair(Supplier leftSupp, - Supplier rightSupp) { - leftSupplier = leftSupp; - rightSupplier = rightSupp; - - leftMaterialized = false; - rightMaterialized = false; - } - - @Override - public IPair bindLeft( - Function> leftBinder) { - Supplier leftSupp = () -> { - if (leftMaterialized) { - return leftValue; - } - - return leftSupplier.get(); - }; - - return new HalfBoundLazyPair<>(leftSupp, leftBinder); - } - - @Override - public IPair bindRight( - Function> rightBinder) { - Supplier rightSupp = () -> { - if (rightMaterialized) { - return rightValue; - } - - return rightSupplier.get(); - }; - - return new HalfBoundLazyPair<>(rightSupp, rightBinder); - } - - @Override - public IPair bind( - BiFunction> binder) { - return new BoundLazyPair<>(leftSupplier, rightSupplier, binder); - } - - @Override - public MergedType merge( - BiFunction merger) { - if (!leftMaterialized) { - leftValue = leftSupplier.get(); - - leftMaterialized = true; - } - - if (!rightMaterialized) { - rightValue = rightSupplier.get(); - - rightMaterialized = true; - } - - return merger.apply(leftValue, rightValue); - } - - @Override - public LeftType getLeft() { - if (!leftMaterialized) { - leftValue = leftSupplier.get(); - - leftMaterialized = true; - } - - return leftValue; - } - - @Override - public RightType getRight() { - if (!rightMaterialized) { - rightValue = rightSupplier.get(); - - rightMaterialized = true; - } - - return rightValue; - } -} diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java deleted file mode 100644 index 87378d7..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/Pair.java +++ /dev/null @@ -1,63 +0,0 @@ -package bjc.utils.data.experimental; - -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * A pair of values, with nothing special about them. - * - * @author ben - * - * @param - * The type of the left value - * @param - * The type of the right value - */ -public class Pair - implements IPair { - private LeftType leftValue; - private RightType rightValue; - - /** - * Create a new pair with both sides set to null - */ - public Pair() { - } - - /** - * Create a new pair with both sides set to the specified values - * - * @param left - * The value of the left side - * @param right - * The value of the right side - */ - public Pair(LeftType left, RightType right) { - leftValue = left; - rightValue = right; - } - - @Override - public IPair bindLeft( - Function> leftBinder) { - return leftBinder.apply(leftValue); - } - - @Override - public IPair bindRight( - Function> rightBinder) { - return rightBinder.apply(rightValue); - } - - @Override - public IPair bind( - BiFunction> binder) { - return binder.apply(leftValue, rightValue); - } - - @Override - public MergedType merge( - BiFunction merger) { - return merger.apply(leftValue, rightValue); - } -} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java b/BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java deleted file mode 100644 index 72e1007..0000000 --- a/BJC-Utils2/src/main/java/bjc/utils/data/experimental/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Experimental redoing of data structures - * - * @author ben - * - */ -package bjc.utils.data.experimental; \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/package-info.java b/BJC-Utils2/src/main/java/bjc/utils/data/package-info.java new file mode 100644 index 0000000..a6f05dd --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/data/package-info.java @@ -0,0 +1,7 @@ +/** + * Experimental redoing of data structures + * + * @author ben + * + */ +package bjc.utils.data; \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/ExtendedMap.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/ExtendedMap.java new file mode 100644 index 0000000..7e4c7fd --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/ExtendedMap.java @@ -0,0 +1,96 @@ +package bjc.utils.funcdata; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +import bjc.utils.funcutils.ListUtils; + +class ExtendedMap + implements IFunctionalMap { + private IFunctionalMap delegate; + + private IFunctionalMap store; + + public ExtendedMap(IFunctionalMap delegate, + IFunctionalMap store) { + this.delegate = delegate; + this.store = store; + } + + @Override + public ValueType put(KeyType key, ValueType val) { + return store.put(key, val); + } + + @Override + public ValueType get(KeyType key) { + if (store.containsKey(key)) { + return store.get(key); + } + + return delegate.get(key); + } + + @Override + public IFunctionalMap mapValues( + Function transformer) { + return new TransformedValueMap<>(this, transformer); + } + + @Override + public boolean containsKey(KeyType key) { + if (store.containsKey(key)) { + return true; + } + + return delegate.containsKey(key); + } + + @Override + public IFunctionalList keyList() { + return ListUtils.mergeLists(store.keyList(), delegate.keyList()); + } + + @Override + public void forEach(BiConsumer action) { + store.forEach(action); + + delegate.forEach(action); + } + + @Override + public ValueType remove(KeyType key) { + return store.remove(key); + } + + @Override + public int getSize() { + return store.getSize() + delegate.getSize(); + } + + @Override + public void forEachKey(Consumer action) { + store.forEachKey(action); + + delegate.forEachKey(action); + } + + @Override + public void forEachValue(Consumer action) { + store.forEachValue(action); + + delegate.forEachValue(action); + } + + @Override + public IFunctionalList valueList() { + return ListUtils.mergeLists(store.valueList(), + delegate.valueList()); + } + + @Override + public IFunctionalMap extend() { + return new ExtendedMap<>(this, new FunctionalMap<>()); + } +} 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 9b388b2..70d04cc 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java @@ -11,10 +11,10 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.IPair; -import bjc.utils.data.experimental.Identity; -import bjc.utils.data.experimental.Pair; +import bjc.utils.data.IHolder; +import bjc.utils.data.IPair; +import bjc.utils.data.Identity; +import bjc.utils.data.Pair; import java.util.ArrayList; @@ -590,4 +590,9 @@ public class FunctionalList implements Cloneable, IFunctionalList { public E[] toArray(E[] arrType) { return wrappedList.toArray(arrType); } + + @Override + public IFunctionalList tail() { + return new FunctionalList<>(wrappedList.subList(1, getSize())); + } } \ No newline at end of file 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 da30064..eaa425b 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java @@ -6,110 +6,21 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; -import bjc.utils.data.experimental.IPair; +import bjc.utils.data.IPair; /** * Basic implementation of {@link IFunctionalMap} * * @author ben * - * @param + * @param * The type of the map's keys - * @param + * @param * The type of the map's values */ -public class FunctionalMap implements IFunctionalMap { - /** - * A map that transforms values from one type to another - * - * @author ben - * - * @param - * The type of the map's keys - * @param - * The type of the map's values - * @param - * The type of the transformed values - */ - private static final class TransformedValueMap - implements IFunctionalMap { - private IFunctionalMap mapToTransform; - private Function transformer; - - public TransformedValueMap(IFunctionalMap destMap, - Function transform) { - mapToTransform = destMap; - transformer = transform; - } - - @Override - public V2 get(K key) { - return transformer.apply(mapToTransform.get(key)); - } - - @Override - public boolean containsKey(K key) { - return mapToTransform.containsKey(key); - } - - @Override - 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 IFunctionalMap mapValues( - Function transform) { - return new TransformedValueMap<>(this, transform); - } - - @Override - public IFunctionalList keyList() { - return mapToTransform.keyList(); - } - - @Override - public void forEach(BiConsumer 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(); - } - - @Override - public void forEachKey(Consumer action) { - mapToTransform.forEachKey(action); - } - - @Override - public void forEachValue(Consumer action) { - mapToTransform.forEachValue((val) -> { - action.accept(transformer.apply(val)); - }); - } - - @Override - public IFunctionalList valueList() { - return mapToTransform.valueList().map(transformer); - } - } - - private Map wrappedMap; +public class FunctionalMap + implements IFunctionalMap { + private Map wrappedMap; /** * Create a new blank functional map @@ -124,7 +35,7 @@ public class FunctionalMap implements IFunctionalMap { * @param wrap * The map to wrap */ - public FunctionalMap(Map wrap) { + public FunctionalMap(Map wrap) { if (wrap == null) { throw new NullPointerException("Map to wrap must not be null"); } @@ -139,10 +50,10 @@ public class FunctionalMap implements IFunctionalMap { * The entries to put into the map */ @SafeVarargs - public FunctionalMap(IPair... entries) { + public FunctionalMap(IPair... entries) { this(); - for (IPair entry : entries) { + for (IPair entry : entries) { entry.doWith((key, val) -> { wrappedMap.put(key, val); }); @@ -155,7 +66,7 @@ public class FunctionalMap implements IFunctionalMap { * @see bjc.utils.funcdata.IFunctionalMap#put(K, V) */ @Override - public V put(K key, V val) { + public ValueType put(KeyType key, ValueType val) { if (key == null) { throw new NullPointerException("Key must not be null"); } @@ -169,7 +80,7 @@ public class FunctionalMap implements IFunctionalMap { * @see bjc.utils.funcdata.IFunctionalMap#get(K) */ @Override - public V get(K key) { + public ValueType get(KeyType key) { if (key == null) { throw new NullPointerException("Key must not be null"); } @@ -189,8 +100,8 @@ public class FunctionalMap implements IFunctionalMap { * Function) */ @Override - public IFunctionalMap mapValues( - Function transformer) { + public IFunctionalMap mapValues( + Function transformer) { if (transformer == null) { throw new NullPointerException("Transformer must not be null"); } @@ -204,7 +115,7 @@ public class FunctionalMap implements IFunctionalMap { * @see bjc.utils.funcdata.IFunctionalMap#containsKey(K) */ @Override - public boolean containsKey(K key) { + public boolean containsKey(KeyType key) { return wrappedMap.containsKey(key); } @@ -214,8 +125,8 @@ public class FunctionalMap implements IFunctionalMap { } @Override - public IFunctionalList keyList() { - FunctionalList keys = new FunctionalList<>(); + public IFunctionalList keyList() { + FunctionalList keys = new FunctionalList<>(); wrappedMap.keySet().forEach((key) -> { keys.add(key); @@ -225,12 +136,12 @@ public class FunctionalMap implements IFunctionalMap { } @Override - public void forEach(BiConsumer action) { + public void forEach(BiConsumer action) { wrappedMap.forEach(action); } @Override - public V remove(K key) { + public ValueType remove(KeyType key) { return wrappedMap.remove(key); } @@ -240,18 +151,18 @@ public class FunctionalMap implements IFunctionalMap { } @Override - public void forEachKey(Consumer action) { + public void forEachKey(Consumer action) { wrappedMap.keySet().forEach(action); } @Override - public void forEachValue(Consumer action) { + public void forEachValue(Consumer action) { wrappedMap.values().forEach(action); } @Override - public IFunctionalList valueList() { - FunctionalList values = new FunctionalList<>(); + public IFunctionalList valueList() { + FunctionalList values = new FunctionalList<>(); wrappedMap.values().forEach((value) -> { values.add(value); @@ -259,4 +170,9 @@ public class FunctionalMap implements IFunctionalMap { return values; } + + @Override + public IFunctionalMap extend() { + return new ExtendedMap<>(this, new FunctionalMap<>()); + } } \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java index 4be7277..f22df57 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalList.java @@ -7,7 +7,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import bjc.utils.data.experimental.IPair; +import bjc.utils.data.IPair; /** * A wrapper over another list that provides eager functional operations @@ -325,4 +325,10 @@ public interface IFunctionalList { * @return An iterable view onto the list */ Iterable toIterable(); + + /** + * Get the tail of this list (the list without the first element + * @return The list without the first element + */ + public IFunctionalList tail(); } \ 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 index c5fe559..0c96a9f 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalMap.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/IFunctionalMap.java @@ -58,7 +58,8 @@ public interface IFunctionalMap { * The function to use to transform values * @return The map where each value will be transformed after lookup */ - IFunctionalMap mapValues(Function transformer); + IFunctionalMap mapValues( + Function transformer); /** * Check if this map contains the specified key @@ -125,4 +126,12 @@ public interface IFunctionalMap { * @return A list of values in this map */ IFunctionalList valueList(); + + /** + * Extends this map, creating a new map that will delegate queries to + * the map, but store any added values itself + * + * @return An extended map + */ + IFunctionalMap extend(); } \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/TransformedValueMap.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/TransformedValueMap.java new file mode 100644 index 0000000..75557fa --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/TransformedValueMap.java @@ -0,0 +1,100 @@ +package bjc.utils.funcdata; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * A map that transforms values from one type to another + * + * @author ben + * + * @param + * The type of the map's keys + * @param + * The type of the map's values + * @param + * The type of the transformed values + */ +final class TransformedValueMap + implements IFunctionalMap { + private IFunctionalMap mapToTransform; + private Function transformer; + + public TransformedValueMap(IFunctionalMap destMap, + Function transform) { + mapToTransform = destMap; + transformer = transform; + } + + @Override + public NewValue get(OldKey key) { + return transformer.apply(mapToTransform.get(key)); + } + + @Override + public boolean containsKey(OldKey key) { + return mapToTransform.containsKey(key); + } + + @Override + public String toString() { + return mapToTransform.toString(); + } + + @Override + public NewValue put(OldKey key, NewValue val) { + throw new UnsupportedOperationException( + "Can't add items to transformed map"); + } + + @Override + public IFunctionalMap mapValues( + Function transform) { + return new TransformedValueMap<>(this, transform); + } + + @Override + public IFunctionalList keyList() { + return mapToTransform.keyList(); + } + + @Override + public void forEach(BiConsumer action) { + mapToTransform.forEach((key, val) -> { + action.accept(key, transformer.apply(val)); + }); + } + + @Override + public NewValue remove(OldKey key) { + return transformer.apply(mapToTransform.remove(key)); + } + + @Override + public int getSize() { + return mapToTransform.getSize(); + } + + @Override + public void forEachKey(Consumer action) { + mapToTransform.forEachKey(action); + } + + @Override + public void forEachValue(Consumer action) { + mapToTransform.forEachValue((val) -> { + action.accept(transformer.apply(val)); + }); + } + + @Override + public IFunctionalList valueList() { + return mapToTransform.valueList().map(transformer); + } + + @Override + public IFunctionalMap extend() { + return new ExtendedMap<>(this, new FunctionalMap<>()); + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/Tree.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/Tree.java index d9938d4..5ee4200 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/Tree.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/Tree.java @@ -6,6 +6,7 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; import bjc.utils.funcdata.bst.TreeLinearizationMethod; +import bjc.utils.funcutils.StringUtils; /** * A node in a homogenous tree. @@ -119,11 +120,11 @@ public class Tree implements ITree { Function leafTransform, Function, NewType>> nodeCollapser) { if (hasChildren) { - Function, NewType> nodeTransformer = nodeCollapser - .apply(data); + Function, NewType> nodeTransformer = + nodeCollapser.apply(data); - IFunctionalList collapsedChildren = children - .map((child) -> { + IFunctionalList collapsedChildren = + children.map((child) -> { return child.collapse(leafTransform, nodeCollapser, (subTreeVal) -> subTreeVal); }); @@ -164,8 +165,9 @@ public class Tree implements ITree { public ITree transformTree( Function transformer) { if (hasChildren) { - IFunctionalList> transformedChildren = children - .map((child) -> child.transformTree(transformer)); + IFunctionalList> transformedChildren = + children.map( + (child) -> child.transformTree(transformer)); return new Tree<>(transformer.apply(data), transformedChildren); @@ -219,8 +221,8 @@ public class Tree implements ITree { Function leafTransformer, Function operatorTransformer) { if (hasChildren) { - IFunctionalList> mappedChildren = children - .map((child) -> { + IFunctionalList> mappedChildren = + children.map((child) -> { return child.rebuildTree(leafTransformer, operatorTransformer); }); @@ -232,4 +234,32 @@ public class Tree implements ITree { return new Tree<>(leafTransformer.apply(data)); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + internalToString(builder, 1, true); + + builder.deleteCharAt(builder.length() - 1); + + return builder.toString(); + } + + protected void internalToString(StringBuilder builder, int indentLevel, + boolean initial) { + if (!initial) { + StringUtils.indentNLevels(builder, indentLevel); + } + + builder.append("Node: "); + builder.append(data == null ? "(null)" : data.toString()); + builder.append("\n"); + + if (hasChildren) { + children.forEach((child) -> { + ((Tree) child).internalToString(builder, + indentLevel + 2, false); + }); + } + } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java index fd09fbb..ea5c72e 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FileUtils.java @@ -1,10 +1,8 @@ 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; @@ -15,39 +13,6 @@ import java.util.function.BiPredicate; * */ public class FileUtils { - private static final class FunctionalFileVisitor - extends SimpleFileVisitor { - private BiPredicate traversalPredicate; - private BiPredicate traversalAction; - - public FunctionalFileVisitor( - BiPredicate traversalPredicate, - BiPredicate 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 * diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/FunctionalFileVisitor.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FunctionalFileVisitor.java new file mode 100644 index 0000000..6d3336a --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/FunctionalFileVisitor.java @@ -0,0 +1,41 @@ +package bjc.utils.funcutils; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.function.BiPredicate; + +final class FunctionalFileVisitor + extends SimpleFileVisitor { + private BiPredicate traversalPredicate; + private BiPredicate traversalAction; + + public FunctionalFileVisitor( + BiPredicate traversalPredicate, + BiPredicate 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; + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/GroupPartIteration.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/GroupPartIteration.java new file mode 100644 index 0000000..3837858 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/GroupPartIteration.java @@ -0,0 +1,64 @@ +package bjc.utils.funcutils; + +import java.util.function.Consumer; +import java.util.function.Function; + +import bjc.utils.data.IHolder; +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; + +/** + * Implements a single group partitioning pass on a list + * + * @author ben + * + * @param + * The type of element in the list being partitioned + */ +final class GroupPartIteration + implements Consumer { + private IFunctionalList> returnedList; + private IHolder> currentPartition; + private IFunctionalList rejectedItems; + private IHolder numberInCurrentPartition; + private int numberPerPartition; + private Function elementCounter; + + public GroupPartIteration( + IFunctionalList> returned, + IHolder> currPart, + IFunctionalList rejects, IHolder numInCurrPart, + int nPerPart, Function eleCount) { + this.returnedList = returned; + this.currentPartition = currPart; + this.rejectedItems = rejects; + this.numberInCurrentPartition = numInCurrPart; + this.numberPerPartition = nPerPart; + this.elementCounter = eleCount; + } + + @Override + public void accept(E value) { + if (numberInCurrentPartition + .unwrap((number) -> number >= numberPerPartition)) { + returnedList.add( + currentPartition.unwrap((partition) -> partition)); + + currentPartition + .transform((partition) -> new FunctionalList<>()); + numberInCurrentPartition.transform((number) -> 0); + } else { + int currentElementCount = elementCounter.apply(value); + + if (numberInCurrentPartition.unwrap((number) -> (number + + currentElementCount) >= numberPerPartition)) { + rejectedItems.add(value); + } else { + currentPartition + .unwrap((partition) -> partition.add(value)); + numberInCurrentPartition.transform( + (number) -> number + currentElementCount); + } + } + } +} \ No newline at end of file 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 977186a..95873e9 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java @@ -2,13 +2,11 @@ package bjc.utils.funcutils; import java.util.ArrayList; import java.util.Deque; -import java.util.function.BiFunction; -import java.util.function.Consumer; import java.util.function.Function; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.IPair; -import bjc.utils.data.experimental.Identity; +import bjc.utils.data.IHolder; +import bjc.utils.data.IPair; +import bjc.utils.data.Identity; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IFunctionalList; @@ -22,146 +20,6 @@ import bjc.utils.funcdata.IFunctionalList; public class ListUtils { private static final int MAX_NTRIESPART = 50; - private static final class TokenDeaffixer implements - BiFunction> { - private String token; - - public TokenDeaffixer(String tok) { - token = tok; - } - - @Override - public IFunctionalList apply(String operatorName, - String operatorRegex) { - if (operatorName == null) { - throw new NullPointerException( - "Operator name must not be null"); - } else if (operatorRegex == null) { - throw new NullPointerException( - "Operator regex must not be null"); - } - - if (StringUtils.containsOnly(token, operatorRegex)) { - return new FunctionalList<>(token); - } else if (token.startsWith(operatorName)) { - return new FunctionalList<>(operatorName, - token.split(operatorRegex)[1]); - } else if (token.endsWith(operatorName)) { - return new FunctionalList<>(token.split(operatorRegex)[0], - operatorName); - } else { - return new FunctionalList<>(token); - } - } - } - - private static final class TokenSplitter implements - BiFunction> { - private String tokenToSplit; - - public TokenSplitter(String tok) { - this.tokenToSplit = tok; - } - - @Override - public IFunctionalList apply(String operatorName, - String operatorRegex) { - if (operatorName == null) { - throw new NullPointerException( - "Operator name must not be null"); - } else if (operatorRegex == null) { - throw new NullPointerException( - "Operator regex must not be null"); - } - - if (tokenToSplit.contains(operatorName)) { - if (StringUtils.containsOnly(tokenToSplit, - operatorRegex)) { - return new FunctionalList<>(tokenToSplit); - } - - IFunctionalList splitTokens = new FunctionalList<>( - tokenToSplit.split(operatorRegex)); - - IFunctionalList result = new FunctionalList<>(); - - int tokenExpansionSize = splitTokens.getSize(); - - splitTokens.forEachIndexed((tokenIndex, token) -> { - - if (tokenIndex != tokenExpansionSize - && tokenIndex != 0) { - result.add(operatorName); - result.add(token); - } else { - result.add(token); - } - }); - - return result; - } - - return new FunctionalList<>(tokenToSplit); - } - } - - /** - * Implements a single group partitioning pass on a list - * - * @author ben - * - * @param - * The type of element in the list being partitioned - */ - private static final class GroupPartIteration - implements Consumer { - private IFunctionalList> returnedList; - private IHolder> currentPartition; - private IFunctionalList rejectedItems; - private IHolder numberInCurrentPartition; - private int numberPerPartition; - private Function elementCounter; - - public GroupPartIteration( - IFunctionalList> returned, - IHolder> currPart, - IFunctionalList rejects, - IHolder numInCurrPart, int nPerPart, - Function eleCount) { - this.returnedList = returned; - this.currentPartition = currPart; - this.rejectedItems = rejects; - this.numberInCurrentPartition = numInCurrPart; - this.numberPerPartition = nPerPart; - this.elementCounter = eleCount; - } - - @Override - public void accept(E value) { - if (numberInCurrentPartition - .unwrap((number) -> number >= numberPerPartition)) { - returnedList.add( - currentPartition.unwrap((partition) -> partition)); - - currentPartition - .transform((partition) -> new FunctionalList<>()); - numberInCurrentPartition.transform((number) -> 0); - } else { - int currentElementCount = elementCounter.apply(value); - - if (numberInCurrentPartition.unwrap((number) -> (number - + currentElementCount) >= numberPerPartition)) { - rejectedItems.add(value); - } else { - currentPartition - .unwrap((partition) -> partition.add(value)); - numberInCurrentPartition.transform( - (number) -> number + currentElementCount); - } - } - } - } - /** * Partition a list into a list of lists, where each element can count * for more than one element in a partition @@ -195,13 +53,14 @@ public class ListUtils { /* * List that holds our results */ - IFunctionalList> returnedList = new FunctionalList<>(); + IFunctionalList> returnedList = + new FunctionalList<>(); /* * List that holds current partition */ - IHolder> currentPartition = new Identity<>( - new FunctionalList<>()); + IHolder> currentPartition = + new Identity<>(new FunctionalList<>()); /* * List that holds elements rejected during current pass */ @@ -215,8 +74,10 @@ public class ListUtils { /* * Run up to a certain number of passes */ - for (int numberOfIterations = 0; numberOfIterations < MAX_NTRIESPART - && !rejectedElements.isEmpty(); numberOfIterations++) { + for (int numberOfIterations = + 0; numberOfIterations < MAX_NTRIESPART + && !rejectedElements + .isEmpty(); numberOfIterations++) { input.forEach(new GroupPartIteration<>(returnedList, currentPartition, rejectedElements, numberInCurrentPartition, numberPerPartition, @@ -264,8 +125,8 @@ public class ListUtils { "Set of operators must not be null"); } - IHolder> returnedList = new Identity<>( - input); + IHolder> returnedList = + new Identity<>(input); operators.forEach((operator) -> returnedList .transform((oldReturn) -> oldReturn.flatMap((token) -> { @@ -295,8 +156,8 @@ public class ListUtils { "Set of operators must not be null"); } - IHolder> returnedList = new Identity<>( - input); + IHolder> returnedList = + new Identity<>(input); operators.forEach((operator) -> returnedList .transform((oldReturn) -> oldReturn.flatMap((token) -> { @@ -372,8 +233,8 @@ public class ListUtils { public static IFunctionalList drawWithReplacement( IFunctionalList list, int numberOfItems, Function rng) { - IFunctionalList selectedItems = new FunctionalList<>( - new ArrayList<>(numberOfItems)); + IFunctionalList selectedItems = + new FunctionalList<>(new ArrayList<>(numberOfItems)); for (int i = 0; i < numberOfItems; i++) { selectedItems.add(list.randItem(rng)); @@ -401,8 +262,8 @@ public class ListUtils { public static IFunctionalList drawWithoutReplacement( IFunctionalList list, int numberOfItems, Function rng) { - IFunctionalList selectedItems = new FunctionalList<>( - new ArrayList<>(numberOfItems)); + IFunctionalList selectedItems = + new FunctionalList<>(new ArrayList<>(numberOfItems)); int totalItems = list.getSize(); @@ -420,4 +281,25 @@ public class ListUtils { return selectedItems; } + + /** + * Merge the contents of a bunch of lists together into a single list + * + * @param + * The type of value in this lists + * @param lists + * The values in the lists to merge + * @return A list containing all the elements of the lists + */ + @SafeVarargs + public static IFunctionalList + mergeLists(IFunctionalList... lists) { + IFunctionalList returnedList = new FunctionalList<>(); + + for (IFunctionalList list : lists) { + list.forEach(returnedList::add); + } + + return returnedList; + } } \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java index ac36d15..c58a42b 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java @@ -57,4 +57,18 @@ public class StringUtils { && !expression.equalsIgnoreCase(operator) && !expression.startsWith(operator); } + + /** + * Indent the string being built in a StringBuilder n levels + * + * @param builder + * The builder to indent in + * @param levels + * The number of levels to indent + */ + public static void indentNLevels(StringBuilder builder, int levels) { + for (int i = 0; i < levels; i++) { + builder.append("\t"); + } + } } diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenDeaffixer.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenDeaffixer.java new file mode 100644 index 0000000..1cf5d44 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenDeaffixer.java @@ -0,0 +1,39 @@ +package bjc.utils.funcutils; + +import java.util.function.BiFunction; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; + +final class TokenDeaffixer implements + BiFunction> { + private String token; + + public TokenDeaffixer(String tok) { + token = tok; + } + + @Override + public IFunctionalList apply(String operatorName, + String operatorRegex) { + if (operatorName == null) { + throw new NullPointerException( + "Operator name must not be null"); + } else if (operatorRegex == null) { + throw new NullPointerException( + "Operator regex must not be null"); + } + + if (StringUtils.containsOnly(token, operatorRegex)) { + return new FunctionalList<>(token); + } else if (token.startsWith(operatorName)) { + return new FunctionalList<>(operatorName, + token.split(operatorRegex)[1]); + } else if (token.endsWith(operatorName)) { + return new FunctionalList<>(token.split(operatorRegex)[0], + operatorName); + } else { + return new FunctionalList<>(token); + } + } +} \ No newline at end of file diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenSplitter.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenSplitter.java new file mode 100644 index 0000000..0da9f7d --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/TokenSplitter.java @@ -0,0 +1,56 @@ +package bjc.utils.funcutils; + +import java.util.function.BiFunction; + +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IFunctionalList; + +final class TokenSplitter implements + BiFunction> { + private String tokenToSplit; + + public TokenSplitter(String tok) { + this.tokenToSplit = tok; + } + + @Override + public IFunctionalList apply(String operatorName, + String operatorRegex) { + if (operatorName == null) { + throw new NullPointerException( + "Operator name must not be null"); + } else if (operatorRegex == null) { + throw new NullPointerException( + "Operator regex must not be null"); + } + + if (tokenToSplit.contains(operatorName)) { + if (StringUtils.containsOnly(tokenToSplit, + operatorRegex)) { + return new FunctionalList<>(tokenToSplit); + } + + IFunctionalList splitTokens = new FunctionalList<>( + tokenToSplit.split(operatorRegex)); + + IFunctionalList result = new FunctionalList<>(); + + int tokenExpansionSize = splitTokens.getSize(); + + splitTokens.forEachIndexed((tokenIndex, token) -> { + + if (tokenIndex != tokenExpansionSize + && tokenIndex != 0) { + result.add(operatorName); + result.add(token); + } else { + result.add(token); + } + }); + + return result; + } + + return new FunctionalList<>(tokenToSplit); + } +} \ No newline at end of file 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 349d9fa..963fb32 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java @@ -12,7 +12,6 @@ import bjc.utils.funcdata.IFunctionalList; * The type of grammar elements to use. */ public class RandomGrammar extends WeightedGrammar { - /** * Create a new random grammar. */ 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 3eae47e..8d31576 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java @@ -3,8 +3,8 @@ package bjc.utils.gen; import java.util.Random; import java.util.function.Function; -import bjc.utils.data.experimental.IPair; -import bjc.utils.data.experimental.Pair; +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; 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 f10ee26..43d9928 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,9 @@ package bjc.utils.gen; import java.util.Random; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.IPair; -import bjc.utils.data.experimental.Identity; +import bjc.utils.data.IHolder; +import bjc.utils.data.IPair; +import bjc.utils.data.Identity; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IFunctionalList; 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 56b4653..7b240b8 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java +++ b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java @@ -7,12 +7,13 @@ import java.util.InputMismatchException; import java.util.Scanner; import java.util.stream.IntStream; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.Identity; +import bjc.utils.data.IHolder; +import bjc.utils.data.Identity; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.FunctionalMap; import bjc.utils.funcdata.IFunctionalList; import bjc.utils.funcdata.IFunctionalMap; +import bjc.utils.funcutils.FuncUtils; /** * An adjacency map representing a graph @@ -67,54 +68,54 @@ public class AdjacencyMap { IFunctionalList vertices = new FunctionalList<>(); - IntStream.range(0, numVertices) - .forEach(element -> vertices.add(element)); + FuncUtils.doTimes(numVertices, + (vertexNo) -> vertices.add(vertexNo)); adjacencyMap = new AdjacencyMap<>(vertices); IHolder row = new Identity<>(0); inputSource.forEachRemaining((strang) -> { - String[] parts = strang.split(" "); + readRow(adjacencyMap, numVertices, row, strang); + }); + } - if (parts.length != numVertices) { - throw new InputMismatchException( - "Must specify a weight for all " + numVertices - + " vertices"); - } + return adjacencyMap; + } - int column = 0; + private static void readRow(AdjacencyMap adjacencyMap, + int numVertices, IHolder row, String strang) { + String[] parts = strang.split(" "); - for (String part : parts) { - int columnWeight; + if (parts.length != numVertices) { + throw new InputMismatchException( + "Must specify a weight for all " + numVertices + + " vertices"); + } - try { - columnWeight = Integer.parseInt(part); - } catch (NumberFormatException nfex) { - InputMismatchException imex = - new InputMismatchException("" + part - + " is not a valid weight."); + int column = 0; - imex.initCause(nfex); + for (String part : parts) { + int columnWeight; - throw imex; - } + try { + columnWeight = Integer.parseInt(part); + } catch (NumberFormatException nfex) { + InputMismatchException imex = new InputMismatchException( + "" + part + " is not a valid weight."); - adjacencyMap.setWeight(row.unwrap(number -> number), - column, columnWeight); + imex.initCause(nfex); - column++; - } + throw imex; + } - row.transform((number) -> { - int newNumber = number + 1; + adjacencyMap.setWeight(row.getValue(), column, + columnWeight); - return newNumber; - }); - }); + column++; } - return adjacencyMap; + row.transform((rowNumber) -> rowNumber + 1); } /** @@ -137,8 +138,9 @@ public class AdjacencyMap { vertices.forEach(vertex -> { IFunctionalMap vertexRow = new FunctionalMap<>(); - vertices.forEach( - targetVertex -> vertexRow.put(targetVertex, 0)); + vertices.forEach(targetVertex -> { + vertexRow.put(targetVertex, 0); + }); adjacencyMap.put(vertex, vertexRow); }); @@ -157,12 +159,12 @@ public class AdjacencyMap { int inverseValue = adjacencyMap.get(targetKey).get(key); if (targetValue != inverseValue) { - result.transform((bool) -> false); + result.replace(false); } }); }); - return result.unwrap(bool -> bool); + return result.getValue(); } /** 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 a72304d..d08c3f9 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java +++ b/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java @@ -10,8 +10,8 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiPredicate; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.Identity; +import bjc.utils.data.IHolder; +import bjc.utils.data.Identity; import bjc.utils.funcdata.FunctionalMap; import bjc.utils.funcdata.IFunctionalList; import bjc.utils.funcdata.IFunctionalMap; @@ -25,7 +25,6 @@ import bjc.utils.funcdata.IFunctionalMap; * The label for vertices */ public class Graph { - /** * The backing representation of the graph */ @@ -157,20 +156,20 @@ public class Graph { // Start at the initial vertex and visit it IHolder sourceVertex = new Identity<>(getInitial()); - visitedVertexes.add(sourceVertex.unwrap(vertex -> vertex)); + visitedVertexes.add(sourceVertex.getValue()); // Make sure we visit all the nodes while (visitedVertexes.size() != getVertexCount()) { // Grab all edges adjacent to the provided edge - forAllEdgesMatchingAt(sourceVertex.unwrap(vertex -> vertex), - (targetVertex, - vertexWeight) -> !visitedVertexes - .contains(targetVertex), - (targetVertex, - vertexWeight) -> availableEdges.add(new Edge<>( - sourceVertex.unwrap(vertex -> vertex), - targetVertex, vertexWeight))); + forAllEdgesMatchingAt(sourceVertex.getValue(), + (targetVertex, vertexWeight) -> { + return !visitedVertexes.contains(targetVertex); + }, (targetVertex, vertexWeight) -> { + availableEdges.add(new Edge<>( + sourceVertex.unwrap(vertex -> vertex), + targetVertex, vertexWeight)); + }); // Get the edge with the minimum distance IHolder> minimumEdge = @@ -178,20 +177,19 @@ public class Graph { // Only consider edges where we haven't visited the target of // the edge - while (visitedVertexes.contains( - minimumEdge.unwrap(vertex -> vertex.getTarget()))) { + while (visitedVertexes.contains(minimumEdge.getValue())) { minimumEdge.transform((edge) -> availableEdges.poll()); } // Add it to our MST - minimumEdges.add(minimumEdge.unwrap(edge -> edge)); + minimumEdges.add(minimumEdge.getValue()); // Advance to the next node sourceVertex.transform((vertex) -> minimumEdge .unwrap(edge -> edge.getTarget())); // Visit this node - visitedVertexes.add(sourceVertex.unwrap(vertex -> vertex)); + visitedVertexes.add(sourceVertex.getValue()); } return minimumEdges; @@ -281,8 +279,10 @@ public class Graph { public static Graph fromEdgeList(List> edges) { Graph g = new Graph<>(); - edges.forEach(edge -> g.addEdge(edge.getSource(), edge.getTarget(), - edge.getDistance(), true)); + edges.forEach(edge -> { + g.addEdge(edge.getSource(), edge.getTarget(), + edge.getDistance(), true); + }); return g; } 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 26a5a78..956c535 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java +++ b/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java @@ -89,26 +89,33 @@ public class ListParameterPanel extends JPanel { if (addAction != null) { addParam = new JButton("Add..."); - addParam.addActionListener( - (event) -> ((DefaultListModel) list.getModel()) - .addElement(addAction.get())); + addParam.addActionListener((event) -> { + DefaultListModel model = + (DefaultListModel) list.getModel(); + + model.addElement(addAction.get()); + }); } JButton editParam = null; if (editAction != null) { editParam = new JButton("Edit..."); - editParam.addActionListener( - (event) -> editAction.accept(list.getSelectedValue())); + editParam.addActionListener((event) -> { + editAction.accept(list.getSelectedValue()); + }); } JButton removeParam = null; if (removeAction != null) { removeParam = new JButton("Remove..."); - removeParam.addActionListener((event) -> removeAction - .accept(((DefaultListModel) list.getModel()) - .remove(list.getSelectedIndex()))); + removeParam.addActionListener((event) -> { + DefaultListModel model = + (DefaultListModel) list.getModel(); + + removeAction.accept(model.remove(list.getSelectedIndex())); + }); } if (addAction != 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 9bb20a5..c31066c 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java @@ -8,8 +8,8 @@ import java.util.Scanner; import java.util.function.BiConsumer; import java.util.function.Consumer; -import bjc.utils.data.experimental.IPair; -import bjc.utils.data.experimental.Pair; +import bjc.utils.data.IPair; +import bjc.utils.data.Pair; import bjc.utils.exceptions.UnknownPragmaException; import bjc.utils.funcdata.FunctionalStringTokenizer; @@ -100,58 +100,13 @@ public class RuleBasedConfigReader { // It's a comment continue; } else if (line.equals("")) { - if (ruleOpen == false) { - // Ignore blank line without an open rule - } else { - if (endRule == null) { - // Nothing happens on rule end - ruleOpen = false; - } else { - endRule.accept(state); - } - - ruleOpen = false; - } + ruleOpen = endRule(state, ruleOpen); + continue; } else if (line.startsWith("\t")) { - if (ruleOpen == false) { - throw new InputMismatchException( - "Can't continue rule with no rule currently open"); - } - - if (continueRule == null) { - throw new InputMismatchException( - "Attempted to continue rule with rule continuation disabled." - + " Check for extraneous tabs"); - } - - continueRule.accept(new FunctionalStringTokenizer( - line.substring(1), " "), state); + continueRule(state, ruleOpen, line); } else { - FunctionalStringTokenizer tokenizer = - new FunctionalStringTokenizer(line, " "); - - String nextToken = tokenizer.nextToken(); - - if (nextToken.equals("pragma")) { - String token = tokenizer.nextToken(); - - pragmas.getOrDefault(token, (tokenzer, stat) -> { - throw new UnknownPragmaException( - "Unknown pragma " + token); - }).accept(tokenizer, state); - } else { - if (ruleOpen == true) { - throw new InputMismatchException( - "Attempted to open a" - + " rule with a rule already open. Make sure rules are" - + " seperated by blank lines"); - } - - startRule.accept(tokenizer, - new Pair<>(nextToken, state)); - ruleOpen = true; - } + ruleOpen = startRule(state, ruleOpen, line); } } } @@ -159,6 +114,65 @@ public class RuleBasedConfigReader { return state; } + private boolean startRule(E state, boolean ruleOpen, String line) { + FunctionalStringTokenizer tokenizer = + new FunctionalStringTokenizer(line, " "); + + String nextToken = tokenizer.nextToken(); + + if (nextToken.equals("pragma")) { + String token = tokenizer.nextToken(); + + pragmas.getOrDefault(token, (tokenzer, stat) -> { + throw new UnknownPragmaException( + "Unknown pragma " + token); + }).accept(tokenizer, state); + } else { + if (ruleOpen == true) { + throw new InputMismatchException("Attempted to open a" + + " rule with a rule already open. Make sure rules are" + + " seperated by blank lines"); + } + + startRule.accept(tokenizer, new Pair<>(nextToken, state)); + ruleOpen = true; + } + return ruleOpen; + } + + private void continueRule(E state, boolean ruleOpen, String line) { + if (ruleOpen == false) { + throw new InputMismatchException( + "Can't continue rule with no rule currently open"); + } + + if (continueRule == null) { + throw new InputMismatchException( + "Attempted to continue rule with rule continuation disabled." + + " Check for extraneous tabs"); + } + + continueRule.accept( + new FunctionalStringTokenizer(line.substring(1), " "), + state); + } + + private boolean endRule(E state, boolean ruleOpen) { + if (ruleOpen == false) { + // Ignore blank line without an open rule + } else { + if (endRule == null) { + // Nothing happens on rule end + ruleOpen = false; + } else { + endRule.accept(state); + } + + ruleOpen = false; + } + return ruleOpen; + } + /** * Set the action to execute when continuing a rule * 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 a60cb01..9c7618b 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java @@ -161,10 +161,15 @@ public class ShuntingYard { operators.put(operatorToken, precedence); } - private boolean isHigherPrec(String operator, String rightOperator) { - return (operators.containsKey(rightOperator) && operators - .get(rightOperator).getPrecedence() >= operators - .get(operator).getPrecedence()); + private boolean isHigherPrec(String leftOperator, + String rightOperator) { + boolean operatorExists = operators.containsKey(rightOperator); + + boolean hasHigherPrecedence = + operators.get(rightOperator).getPrecedence() >= operators + .get(leftOperator).getPrecedence(); + + return (operatorExists && hasHigherPrecedence); } /** diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenTransformer.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenTransformer.java new file mode 100644 index 0000000..4db5e76 --- /dev/null +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenTransformer.java @@ -0,0 +1,94 @@ +package bjc.utils.parserutils; + +import java.util.Deque; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +import bjc.utils.data.IHolder; +import bjc.utils.data.IPair; +import bjc.utils.data.Pair; +import bjc.utils.funcdata.ITree; +import bjc.utils.funcdata.Tree; + +final class TokenTransformer implements Consumer { + private final class OperatorHandler + implements UnaryOperator>, ITree>> { + private T element; + + public OperatorHandler(T element) { + this.element = element; + } + + @Override + public IPair>, ITree> + apply(IPair>, ITree> pair) { + return pair.bind((queuedASTs, currentAST) -> { + return handleOperator(queuedASTs); + }); + } + + private IPair>, ITree> + handleOperator(Deque> queuedASTs) { + ITree newAST; + + if (isSpecialOperator.test(element)) { + newAST = handleSpecialOperator.apply(queuedASTs); + } else { + if (queuedASTs.size() < 2) { + throw new IllegalStateException( + "Attempted to parse binary operator without enough operands.\n" + + "Problem operator is " + element + + "\nPossible operand is: \n\t" + + queuedASTs.peek()); + } + + ITree rightAST = queuedASTs.pop(); + ITree leftAST = queuedASTs.pop(); + + newAST = new Tree<>(element, leftAST, rightAST); + } + + queuedASTs.push(newAST); + + return new Pair<>(queuedASTs, newAST); + } + } + + private IHolder>, ITree>> initialState; + private Predicate operatorPredicate; + private Predicate isSpecialOperator; + private Function>, ITree> handleSpecialOperator; + + public TokenTransformer( + IHolder>, ITree>> initialState, + Predicate operatorPredicate, Predicate isSpecialOperator, + Function>, ITree> handleSpecialOperator) { + this.initialState = initialState; + this.operatorPredicate = operatorPredicate; + this.isSpecialOperator = isSpecialOperator; + this.handleSpecialOperator = handleSpecialOperator; + } + + @Override + public void accept(T element) { + if (operatorPredicate.test(element)) { + initialState.transform(new OperatorHandler(element)); + } else { + ITree newAST = new Tree<>(element); + + initialState.doWith((pair) -> { + pair.doWith((queue, currentAST) -> { + queue.push(newAST); + }); + }); + + initialState.transform((pair) -> { + return pair.bind((queue, currentAST) -> { + return new Pair<>(queue, newAST); + }); + }); + } + } +} \ No newline at end of file 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 52299bb..efd0394 100644 --- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java +++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java @@ -2,18 +2,15 @@ package bjc.utils.parserutils; import java.util.Deque; import java.util.LinkedList; -import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.UnaryOperator; -import bjc.utils.data.experimental.IHolder; -import bjc.utils.data.experimental.IPair; -import bjc.utils.data.experimental.Identity; -import bjc.utils.data.experimental.Pair; +import bjc.utils.data.IHolder; +import bjc.utils.data.IPair; +import bjc.utils.data.Identity; +import bjc.utils.data.Pair; import bjc.utils.funcdata.IFunctionalList; import bjc.utils.funcdata.ITree; -import bjc.utils.funcdata.Tree; /** * Creates a parse tree from a postfix expression @@ -22,88 +19,6 @@ import bjc.utils.funcdata.Tree; * */ public class TreeConstructor { - private static final class TokenTransformer implements Consumer { - private final class OperatorHandler implements - UnaryOperator>, ITree>> { - private T element; - - public OperatorHandler(T element) { - this.element = element; - } - - @Override - public IPair>, ITree> apply( - IPair>, ITree> pair) { - return pair.bind((queuedASTs, currentAST) -> { - return handleOperator(queuedASTs); - }); - } - - private IPair>, ITree> handleOperator( - Deque> queuedASTs) { - ITree newAST; - - if (isSpecialOperator.test(element)) { - newAST = handleSpecialOperator.apply(queuedASTs); - } else { - if (queuedASTs.size() < 2) { - throw new IllegalStateException( - "Attempted to parse binary operator without enough operands.\n" - + "Problem operator is " + element - + "\nPossible operand is: \n\t" - + queuedASTs.peek()); - } - - ITree rightAST = queuedASTs.pop(); - ITree leftAST = queuedASTs.pop(); - - newAST = new Tree<>(element, leftAST, rightAST); - } - - queuedASTs.push(newAST); - - return new Pair<>(queuedASTs, newAST); - } - } - - private IHolder>, ITree>> initialState; - private Predicate operatorPredicate; - private Predicate isSpecialOperator; - private Function>, ITree> handleSpecialOperator; - - public TokenTransformer( - IHolder>, ITree>> initialState, - Predicate operatorPredicate, - Predicate isSpecialOperator, - Function>, ITree> handleSpecialOperator) { - this.initialState = initialState; - this.operatorPredicate = operatorPredicate; - this.isSpecialOperator = isSpecialOperator; - this.handleSpecialOperator = handleSpecialOperator; - } - - @Override - public void accept(T element) { - if (operatorPredicate.test(element)) { - initialState.transform(new OperatorHandler(element)); - } else { - ITree newAST = new Tree<>(element); - - initialState.doWith((pair) -> { - pair.doWith((queue, currentAST) -> { - queue.push(newAST); - }); - }); - - initialState.transform((pair) -> { - return pair.bind((queue, currentAST) -> { - return new Pair<>(queue, newAST); - }); - }); - } - } - } - /** * Construct a tree from a list of tokens in postfix notation * @@ -161,15 +76,15 @@ public class TreeConstructor { "Special operator determiner must not be null"); } - IHolder>, ITree>> initialState = new Identity<>( - new Pair<>(new LinkedList<>(), null)); + IHolder>, ITree>> initialState = + new Identity<>(new Pair<>(new LinkedList<>(), null)); tokens.forEach( new TokenTransformer<>(initialState, operatorPredicate, isSpecialOperator, handleSpecialOperator)); return initialState.unwrap((pair) -> { - return pair.merge((queue, currentAST) -> currentAST); + return pair.getRight(); }); } } -- cgit v1.2.3