summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc
diff options
context:
space:
mode:
Diffstat (limited to 'base/src/main/java/bjc')
-rw-r--r--base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java6
-rw-r--r--base/src/main/java/bjc/utils/graph/Graphs.java67
-rw-r--r--base/src/main/java/bjc/utils/ioutils/DuplicateKeys.java21
-rw-r--r--base/src/main/java/bjc/utils/ioutils/InvalidLineFormat.java20
-rw-r--r--base/src/main/java/bjc/utils/ioutils/SimpleProperties.java51
-rw-r--r--base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java2
-rw-r--r--base/src/main/java/bjc/utils/ioutils/blocks/package-info.java8
-rw-r--r--base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java23
-rw-r--r--base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java28
-rw-r--r--base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java191
-rw-r--r--base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java3
11 files changed, 316 insertions, 104 deletions
diff --git a/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java b/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java
index 1c50df3..6b4bbb3 100644
--- a/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java
+++ b/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java
@@ -114,9 +114,9 @@ public class BlockReaderCLI {
sources.put("stdio", new InputStreamReader(System.in));
- Scanner input = new Scanner(System.in);
- reader.run(input, "console", true);
- input.close();
+ try (Scanner input = new Scanner(System.in)) {
+ reader.run(input, "console", true);
+ }
}
/**
diff --git a/base/src/main/java/bjc/utils/graph/Graphs.java b/base/src/main/java/bjc/utils/graph/Graphs.java
new file mode 100644
index 0000000..2844a68
--- /dev/null
+++ b/base/src/main/java/bjc/utils/graph/Graphs.java
@@ -0,0 +1,67 @@
+package bjc.utils.graph;
+
+import java.util.*;
+
+import bjc.data.Holder;
+import bjc.data.Identity;
+
+public class Graphs {
+ /**
+ * Uses Prim's algorithm to calculate a MST for the graph.
+ *
+ * If the graph is non-connected, this will lead to unpredictable results.
+ *
+ * @return A list of edges that constitute the MST.
+ */
+ public static <T, L> List<Edge<T, L>> getMinimumSpanningTree(Graph<T, L> grap, Comparator<L> comp) {
+ /* Set of all of the currently available edges. */
+ final Queue<Edge<T, L>> available = new PriorityQueue<>(10,
+ (left, right) -> comp.compare(left.getDistance(), right.getDistance()));
+
+ /* The MST of the graph. */
+ final List<Edge<T, L>> minimums = new ArrayList<>();
+
+ /* The set of all of the visited vertices. */
+ final Set<T> visited = new HashSet<>();
+
+ /* Start at the initial vertex and visit it */
+ final Holder<T> source = new Identity<>(grap.getInitial());
+
+ visited.add(source.getValue());
+
+ /* Make sure we visit all the nodes. */
+ while (visited.size() != grap.getVertexCount()) {
+ /* Grab all edges adjacent to the provided edge. */
+
+ grap.forAllEdgesMatchingAt(source.getValue(),
+ (target, weight) -> !visited.contains(target),
+ (target, weight) -> {
+ final T vert = source.unwrap(vertex -> vertex);
+
+ available.add(new Edge<>(vert, target, weight));
+ }
+ );
+
+ /* Get the edge with the minimum distance. */
+ final Holder<Edge<T, L>> minimum = new Identity<>(available.poll());
+
+ /*
+ * Only consider edges where we haven't visited the target of the edge.
+ */
+ while (visited.contains(minimum.getValue().getTarget())) {
+ minimum.transform(edge -> available.poll());
+ }
+
+ /* Add it to our MST. */
+ minimums.add(minimum.getValue());
+
+ /* Advance to the next node. */
+ source.transform(vertex -> minimum.unwrap(edge -> edge.getTarget()));
+
+ /* Visit this node. */
+ visited.add(source.getValue());
+ }
+
+ return minimums;
+ }
+}
diff --git a/base/src/main/java/bjc/utils/ioutils/DuplicateKeys.java b/base/src/main/java/bjc/utils/ioutils/DuplicateKeys.java
new file mode 100644
index 0000000..604cc69
--- /dev/null
+++ b/base/src/main/java/bjc/utils/ioutils/DuplicateKeys.java
@@ -0,0 +1,21 @@
+package bjc.utils.ioutils;
+
+/**
+ * Exception thrown when there is a duplicate key, when they are forbidden.
+ *
+ * @author 15405
+ *
+ */
+public class DuplicateKeys extends RuntimeException {
+ private static final long serialVersionUID = -5521190136366024804L;
+
+ /**
+ * Create a new duplicate key exception.
+ *
+ * @param keyName
+ * The name of the key that has been duplicated.
+ */
+ public DuplicateKeys(String keyName) {
+ super(String.format("Duplicate value encountered for key '%s'", keyName));
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/ioutils/InvalidLineFormat.java b/base/src/main/java/bjc/utils/ioutils/InvalidLineFormat.java
new file mode 100644
index 0000000..2763eb1
--- /dev/null
+++ b/base/src/main/java/bjc/utils/ioutils/InvalidLineFormat.java
@@ -0,0 +1,20 @@
+package bjc.utils.ioutils;
+
+/**
+ * Exception thrown when a line is formattted incorrectly.
+ * @author Ben Culkin
+ *
+ */
+public class InvalidLineFormat extends RuntimeException {
+ private static final long serialVersionUID = 5332131472090792841L;
+
+ /**
+ * Create a new exception for an incorrectly formatted line.
+ * @param lne The line that was incorrectly formatted.
+ */
+ public InvalidLineFormat(String lne) {
+ super(String.format(
+ "Line '%s' is improperly formatted.\n\tExpected format is a string key, followed by a single space, followed by the value",
+ ""));
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/ioutils/SimpleProperties.java b/base/src/main/java/bjc/utils/ioutils/SimpleProperties.java
index d380866..0aa18b4 100644
--- a/base/src/main/java/bjc/utils/ioutils/SimpleProperties.java
+++ b/base/src/main/java/bjc/utils/ioutils/SimpleProperties.java
@@ -17,45 +17,6 @@ import java.util.Set;
*
*/
public class SimpleProperties implements Map<String, String> {
- /**
- * Exception thrown when there is a duplicate key, when they are forbidden.
- *
- * @author 15405
- *
- */
- public static class DuplicateKeys extends RuntimeException {
- private static final long serialVersionUID = -5521190136366024804L;
-
- /**
- * Create a new duplicate key exception.
- *
- * @param keyName
- * The name of the key that has been duplicated.
- */
- public DuplicateKeys(String keyName) {
- super(String.format("Duplicate value encountered for key '%s'", keyName));
- }
- }
-
- /**
- * Exception thrown when a line is formattted incorrectly.
- * @author Ben Culkin
- *
- */
- public static class InvalidLineFormat extends RuntimeException {
- private static final long serialVersionUID = 5332131472090792841L;
-
- /**
- * Create a new exception for an incorrectly formatted line.
- * @param lne The line that was incorrectly formatted.
- */
- public InvalidLineFormat(String lne) {
- super(String.format(
- "Line '%s' is improperly formatted.\n\tExpected format is a string key, followed by a single space, followed by the value",
- ""));
- }
- }
-
private final Map<String, String> props;
/**
@@ -170,20 +131,17 @@ public class SimpleProperties implements Map<String, String> {
return props.isEmpty();
}
- @SuppressWarnings("unlikely-arg-type")
- @Override
+ @Override
public boolean containsKey(final Object key) {
return props.containsKey(key);
}
- @SuppressWarnings("unlikely-arg-type")
- @Override
+ @Override
public boolean containsValue(final Object value) {
return props.containsValue(value);
}
- @SuppressWarnings("unlikely-arg-type")
- @Override
+ @Override
public String get(final Object key) {
return props.get(key);
}
@@ -193,8 +151,7 @@ public class SimpleProperties implements Map<String, String> {
return props.put(key, value);
}
- @SuppressWarnings("unlikely-arg-type")
- @Override
+ @Override
public String remove(final Object key) {
return props.remove(key);
}
diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java b/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java
index 265a781..9617ebd 100644
--- a/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java
+++ b/base/src/main/java/bjc/utils/ioutils/blocks/SerialBlockReader.java
@@ -102,6 +102,8 @@ public class SerialBlockReader implements BlockReader {
@Override
public void close() throws IOException {
while (!readerQueue.isEmpty()) {
+ // We are explicitly closing these
+ @SuppressWarnings("resource")
final BlockReader reader = readerQueue.pop();
reader.close();
diff --git a/base/src/main/java/bjc/utils/ioutils/blocks/package-info.java b/base/src/main/java/bjc/utils/ioutils/blocks/package-info.java
index 3d05ed4..d321725 100644
--- a/base/src/main/java/bjc/utils/ioutils/blocks/package-info.java
+++ b/base/src/main/java/bjc/utils/ioutils/blocks/package-info.java
@@ -2,16 +2,16 @@
* is structured as a series of 'blocks' or records.
* <p>
*
- * The most fundamental unit here is that of {@link Block}. Each {@link
- * BlockReader} will yield a sequence of these, which contain a piece of text
+ * The most fundamental unit here is that of {@link bjc.utils.ioutils.blocks.Block}. Each {@link
+ * bjc.utils.ioutils.blocks.BlockReader} will yield a sequence of these, which contain a piece of text
* as its contents, as well as the beginning/ending line for that block.
*
- * There are a number of different types of {@link BlockReader}, which are
+ * There are a number of different types of {@link bjc.utils.ioutils.blocks.BlockReader}, which are
* summarized here.
* </p>
*
* <dl>
- * <dt>{@link SimpleBlockReader}</dt>
+ * <dt>{@link bjc.utils.ioutils.blocks.SimpleBlockReader}</dt>
* <dd>
* The most basic form of BlockReader. This uses a regular expression to
* delimit input reader from a {@link Reader} into a series of blocks.
diff --git a/base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java b/base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java
new file mode 100644
index 0000000..535825e
--- /dev/null
+++ b/base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java
@@ -0,0 +1,23 @@
+package bjc.utils.parserutils.pattern;
+
+import java.util.function.Supplier;
+
+final class FunctionalPatternPart implements PatternPart {
+ private final Supplier<String> func;
+ private final boolean canOptimize;
+
+ FunctionalPatternPart(Supplier<String> func, boolean canOptimize) {
+ this.func = func;
+ this.canOptimize = canOptimize;
+ }
+
+ @Override
+ public String toRegex() {
+ return func.get();
+ }
+
+ @Override
+ public boolean canOptimize() {
+ return canOptimize;
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java b/base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java
new file mode 100644
index 0000000..2f3b16d
--- /dev/null
+++ b/base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java
@@ -0,0 +1,28 @@
+package bjc.utils.parserutils.pattern;
+
+import java.util.StringJoiner;
+
+final class JoinerPatternPart implements PatternPart {
+ private final PatternPart[] parts;
+ private final String joiner;
+
+ JoinerPatternPart(PatternPart[] parts, String joiner) {
+ this.parts = parts;
+ this.joiner = joiner;
+ }
+
+ @Override
+ public String toRegex() {
+ StringJoiner sj = new StringJoiner(joiner);
+ for (PatternPart part : parts) sj.add(part.toRegex());
+ return sj.toString();
+ }
+
+ @Override
+ public boolean canOptimize() {
+ for (PatternPart part : parts)
+ if (!part.canOptimize()) return false;
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java b/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java
index 6661072..2fd59ca 100644
--- a/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java
+++ b/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java
@@ -1,12 +1,14 @@
package bjc.utils.parserutils.pattern;
-import java.util.StringJoiner;
import java.util.function.Supplier;
import java.util.regex.*;
/**
* Builder interface for regex patterns.
*
+ * Note that you may need to add explicit non-grouping to get things to work
+ * right, based on the precedence of your regex operators.
+ *
* @author bjculkin
*
*/
@@ -17,27 +19,37 @@ public interface PatternPart {
* @return The regex this part represents.
*/
public String toRegex();
-
+
+ /**
+ * Can this regex be optimized?
+ *
+ * @return Whether or not this regex can be optimized to a string
+ */
public boolean canOptimize();
-
+
+ /**
+ * Create a new pattern part from component bits.
+ *
+ * @param canOptimize Whether this part can be optimized
+ * @param func The function that provides the regex text
+ *
+ * @return A pattern part w/ the given body
+ */
static PatternPart part(boolean canOptimize, Supplier<String> func) {
- return new PatternPart() {
-
- @Override
- public String toRegex() {
- return func.get();
- }
-
- @Override
- public boolean canOptimize() {
- return canOptimize;
- }
- };
- }
-
+ return new FunctionalPatternPart(func, canOptimize);
+ }
+
+ /**
+ * Create a new variable pattern part.
+ *
+ * @param source The function which supplies the text.
+ *
+ * @return A part that retrieves its bits from the given source
+ */
static PatternPart var(Supplier<String> source) {
return part(false, source);
}
+
/**
* Create a 'raw' pattern part, which just echoes the given string.
*
@@ -48,26 +60,20 @@ public interface PatternPart {
static PatternPart raw(String str) {
return part(true, () -> str);
}
-
+
+ /**
+ * Create a pattern composed of other patterns, interspersed with the given
+ * string.
+ *
+ * @param joiner The string to use as a joiner.
+ * @param parts The composed pattern parts.
+ *
+ * @return The given patterns composed by the parts, joined by `joiner`.
+ */
static PatternPart joining(String joiner, PatternPart... parts) {
- return new PatternPart() {
-
- @Override
- public String toRegex() {
- StringJoiner sj = new StringJoiner(joiner);
- for (PatternPart part : parts) sj.add(part.toRegex());
- return sj.toString();
- }
-
- @Override
- public boolean canOptimize() {
- for (PatternPart part : parts)
- if (!part.canOptimize()) return false;
-
- return true;
- }
- };
+ return new JoinerPatternPart(parts, joiner);
}
+
/**
* Create a pattern part which matches the given string.
*
@@ -78,7 +84,7 @@ public interface PatternPart {
static PatternPart literal(String str) {
return part(true, () -> Pattern.quote(str));
}
-
+
/**
* Create a pattern part which matches a single digit.
*
@@ -87,60 +93,149 @@ public interface PatternPart {
static PatternPart digit() {
return raw("\\d");
}
-
+
+ /**
+ * Create a character class pattern
+ *
+ * @param chars The characters that make up the class.
+ *
+ * @return A pattern representing the character class.
+ */
static PatternPart cclass(char... chars) {
return part(true, () -> {
StringBuilder sb = new StringBuilder("[");
- for (char ch : chars) sb.append(ch);
+ for (char ch : chars)
+ sb.append(ch);
sb.append("]");
return sb.toString();
});
}
-
+
+ /**
+ * Represents an inverted character class.
+ *
+ * @param chars The characters for the class not to include.
+ *
+ * @return A pattern representing a class that doesn't match the characters.
+ */
static PatternPart notCClass(char... chars) {
return part(true, () -> {
StringBuilder sb = new StringBuilder("[^");
- for (char ch : chars) sb.append(ch);
+ for (char ch : chars)
+ sb.append(ch);
sb.append("]");
return sb.toString();
});
}
-
+
+ /**
+ * Represents a pattern that matches any non-space character.
+ *
+ * @return A pattern that matches any non-space character.
+ */
static PatternPart nonspace() {
return raw("\\S");
}
-
+
+ /**
+ * Concatenate a series of pattern parts with whitespace.
+ *
+ * @param parts The parts to join
+ *
+ * @return A pattern that matches each of the given parts, separated by
+ * whitespace.
+ */
static PatternPart concat(PatternPart... parts) {
return joining(" ", parts);
}
-
+
+ /**
+ * Create a pattern which matches one of the given patterns.
+ *
+ * @param parts The possible patterns to match.
+ *
+ * @return A pattern which matches one of the given patterns.
+ */
static PatternPart alternate(PatternPart... parts) {
return joining("|", parts);
}
-
+
+ /**
+ * Create a pattern which matches the given pattern zero or more times.
+ *
+ * @param part The pattern to repeat
+ *
+ * @return A pattern which matches the given one zero or more times.
+ */
static PatternPart repeat(PatternPart part) {
return part(part.canOptimize(), () -> part.toRegex() + "*");
}
-
+
+ /**
+ * Create a pattern which matches the given one zero or more times.
+ *
+ * @param part The pattern to be optional.
+ *
+ * @return A pattern where the part is optional
+ */
static PatternPart optional(PatternPart part) {
return part(part.canOptimize(), () -> part.toRegex() + "?");
}
-
+
+ /**
+ * Create a pattern which matches the given pattern one or more times.
+ *
+ * @param part The pattern to repeat.
+ *
+ * @return A pattern which matches the given one one or more times.
+ */
static PatternPart repeatAtLeastOnce(PatternPart part) {
return part(part.canOptimize(), () -> part.toRegex() + "*");
}
-
+
+ /**
+ * Surround the given pattern with strings.
+ *
+ * @param lhs The left-hand side of the pattern.
+ * @param rhs The right-hand side of the pattern.
+ * @param part The pattern to match.
+ *
+ * @return A pattern surrounded by the given strings.
+ */
static PatternPart surround(String lhs, String rhs, PatternPart part) {
return part(part.canOptimize(), () -> lhs + part.toRegex() + rhs);
}
+
+ /**
+ * Wrap the given pattern in a capturing group.
+ *
+ * @param part The pattern to wrap.
+ *
+ * @return The pattern, wrapped in a capturing group
+ */
static PatternPart group(PatternPart part) {
return surround("(", ")", part);
}
+ /**
+ * Wrap the given pattern in a named-capturing group.
+ *
+ * @param groupName The name of the group
+ * @param part The pattern to wrap.
+ *
+ * @return A pattern wrap in a named-capturing group.
+ */
static PatternPart namedGroup(String groupName, PatternPart part) {
return surround("(<" + groupName + ">", ")", part);
}
-
+
+ /**
+ * Wrap the given pattern in a non-capturing group.
+ *
+ * @param part The pattern to wrap.
+ *
+ * @return A pattern wrap in a non-capturing group.
+ */
static PatternPart nonCaptureGroup(PatternPart part) {
return surround("(?:", ")", part);
}
diff --git a/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java b/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java
index 176f588..28e9cd7 100644
--- a/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java
+++ b/base/src/main/java/bjc/utils/patterns/MutablePatternMatcher.java
@@ -79,8 +79,7 @@ public class MutablePatternMatcher<ReturnType, InputType>
*
* @return Whether or not the pattern was removed.
*/
- @SuppressWarnings("unlikely-arg-type")
- public boolean removePattern(ComplexPattern<ReturnType, ?, InputType> pattern) {
+ public boolean removePattern(ComplexPattern<ReturnType, ?, InputType> pattern) {
return patterns.remove(pattern);
}
}