summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2016-04-03 19:22:48 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2016-04-03 19:22:48 -0400
commit1c8bc7132d980c1ff2dbd6b9af579c3b2fd8c63e (patch)
treea29777f07ebd81fbef61b5ae02f13f1a9d8f65a2 /BJC-Utils2/src/main
parenta023de85aa08c8f2b8b2441c6b14064eabee2775 (diff)
General code refactoring and maintenance
Diffstat (limited to 'BJC-Utils2/src/main')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java8
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java2
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java2
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/components/IDescribedComponent.java2
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/components/package-info.java7
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java19
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/data/GenHolder.java20
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/data/Pair.java13
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/data/lazy/ILazy.java35
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java57
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyPair.java77
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java123
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java151
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java47
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java11
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java12
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java27
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java129
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java6
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java109
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java7
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java118
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java62
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java26
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java72
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java43
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/SimpleFileChooser.java32
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java8
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/SimpleTitledBorder.java1
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java12
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java179
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java110
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java119
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java151
37 files changed, 1480 insertions, 329 deletions
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 9d18390..5ab87bb 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/components/ComponentDescriptionFileParser.java
@@ -26,7 +26,7 @@ public class ComponentDescriptionFileParser {
reader.addPragma("name", (tokenizer, state) -> {
if (!tokenizer.hasMoreTokens()) {
throw new PragmaFormatException(
- "Pragma name requires at least one argument");
+ "Pragma name requires one string argument");
} else {
state.setName(ListUtils.collapseTokens(
tokenizer.toList((strang) -> strang)));
@@ -36,7 +36,7 @@ public class ComponentDescriptionFileParser {
reader.addPragma("author", (tokenizer, state) -> {
if (!tokenizer.hasMoreTokens()) {
throw new PragmaFormatException(
- "Pragma author requires at least one argument");
+ "Pragma author requires one string argument");
} else {
state.setAuthor(ListUtils.collapseTokens(
tokenizer.toList((strang) -> strang)));
@@ -46,7 +46,7 @@ public class ComponentDescriptionFileParser {
reader.addPragma("description", (tokenizer, state) -> {
if (!tokenizer.hasMoreTokens()) {
throw new PragmaFormatException(
- "Pragma description requires at least one argument");
+ "Pragma description requires one string argument");
} else {
state.setDescription(ListUtils.collapseTokens(
tokenizer.toList((strang) -> strang)));
@@ -56,7 +56,7 @@ public class ComponentDescriptionFileParser {
reader.addPragma("version", (tokenizer, state) -> {
if (!tokenizer.hasMoreTokens()) {
throw new PragmaFormatException(
- "Pragma name requires at least one argument");
+ "Pragma name requires one integer argument");
} else {
String token = tokenizer.nextToken();
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 d808b8e..4b8d87b 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/components/FileComponentRepository.java
@@ -123,4 +123,4 @@ public class FileComponentRepository<E extends IDescribedComponent>
public E getComponentByName(String name) {
return components.get(name);
}
-}
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java b/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java
index 04ff51b..135e609 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/components/IComponentRepository.java
@@ -44,4 +44,4 @@ public interface IComponentRepository<E extends IDescribedComponent> {
* @return The source from which these components came
*/
public String getSource();
-}
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/components/IDescribedComponent.java b/BJC-Utils2/src/main/java/bjc/utils/components/IDescribedComponent.java
index 15be70d..c3576a3 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/components/IDescribedComponent.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/components/IDescribedComponent.java
@@ -50,4 +50,4 @@ public interface IDescribedComponent {
public default int getVersion() {
return 1;
}
-}
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/components/package-info.java b/BJC-Utils2/src/main/java/bjc/utils/components/package-info.java
new file mode 100644
index 0000000..5ed7777
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/components/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * This package contains utilities for components
+ *
+ * @author ben
+ *
+ */
+package bjc.utils.components; \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java b/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java
index 056f775..458aece 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/configuration/ConfigFile.java
@@ -19,6 +19,7 @@ public class ConfigFile {
/**
* A category in a configuration file
+ *
* @author ben
*
*/
@@ -32,6 +33,14 @@ public class ConfigFile {
children = new HashMap<>();
}
+ /**
+ * Add a child category to this category
+ *
+ * @param childName
+ * The name of the child
+ * @param child
+ * The child category
+ */
public void addChild(String childName, ConfigCategory child) {
children.put(childName, child);
}
@@ -64,14 +73,16 @@ public class ConfigFile {
continue;
} else if (SourceVersion.isName(currentTokens[0])
&& currentTokens[1].equals("{")) {
- topLevelCategories.put(currentTokens[0], parseCategory(currentTokens[0], scn));
+ topLevelCategories.put(currentTokens[0],
+ parseCategory(currentTokens[0], scn));
}
}
return returnedFile;
}
- private static ConfigCategory parseCategory(String categoryName,
+ private static ConfigCategory parseCategory(
+ @SuppressWarnings("unused") String categoryName,
Scanner inputSource) {
ConfigCategory category = new ConfigCategory();
@@ -119,7 +130,8 @@ public class ConfigFile {
return category;
}
- private static void parseEntry(ConfigCategory category,
+ private static void parseEntry(
+ @SuppressWarnings("unused") ConfigCategory category,
String[] entryParts) {
String entry = String.join("", entryParts);
@@ -128,6 +140,7 @@ public class ConfigFile {
String[] expSpecifiers = expParts[0].split(":");
String expType = expSpecifiers[0];
+ @SuppressWarnings("unused")
String expName = expSpecifiers[1];
switch (expType) {
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/GenHolder.java b/BJC-Utils2/src/main/java/bjc/utils/data/GenHolder.java
index 6854440..e042554 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/data/GenHolder.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/data/GenHolder.java
@@ -46,6 +46,10 @@ public class GenHolder<T> implements IHolder<T> {
*/
@Override
public void doWith(Consumer<T> action) {
+ if (action == null) {
+ throw new NullPointerException("Action must be non-null");
+ }
+
action.accept(heldValue);
}
@@ -56,6 +60,10 @@ public class GenHolder<T> implements IHolder<T> {
*/
@Override
public <NewT> IHolder<NewT> map(Function<T, NewT> transformer) {
+ if (transformer == null) {
+ throw new NullPointerException("Transformer must be non-null");
+ }
+
return new GenHolder<>(transformer.apply(heldValue));
}
@@ -66,6 +74,10 @@ public class GenHolder<T> implements IHolder<T> {
*/
@Override
public IHolder<T> transform(Function<T, T> transformer) {
+ if (transformer == null) {
+ throw new NullPointerException("Transformer must be non-null");
+ }
+
heldValue = transformer.apply(heldValue);
return this;
@@ -78,11 +90,19 @@ public class GenHolder<T> implements IHolder<T> {
*/
@Override
public <E> E unwrap(Function<T, E> unwrapper) {
+ if (unwrapper == null) {
+ throw new NullPointerException("Unwrapper must be null");
+ }
+
return unwrapper.apply(heldValue);
}
@Override
public String toString() {
+ if (heldValue == null) {
+ return "(null)";
+ }
+
return heldValue.toString();
}
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java b/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java
index b5ad953..97cb195 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/data/Pair.java
@@ -56,6 +56,11 @@ public class Pair<L, R> implements IPair<L, R> {
@Override
public <L2, R2> IPair<L2, R2> apply(Function<L, L2> leftTransformer,
Function<R, R2> rightTransformer) {
+ if (leftTransformer == null || rightTransformer == null) {
+ throw new NullPointerException(
+ "Transformers must be non-null");
+ }
+
return new Pair<>(leftTransformer.apply(leftValue),
rightTransformer.apply(rightValue));
}
@@ -67,6 +72,10 @@ public class Pair<L, R> implements IPair<L, R> {
*/
@Override
public void doWith(BiConsumer<L, R> action) {
+ if (action == null) {
+ throw new NullPointerException("Action must be non-null");
+ }
+
action.accept(leftValue, rightValue);
}
@@ -77,6 +86,10 @@ public class Pair<L, R> implements IPair<L, R> {
*/
@Override
public <E> E merge(BiFunction<L, R, E> merger) {
+ if (merger == null) {
+ throw new NullPointerException("Merger must be non-null");
+ }
+
return merger.apply(leftValue, rightValue);
}
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/ILazy.java b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/ILazy.java
new file mode 100644
index 0000000..a4fab67
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/ILazy.java
@@ -0,0 +1,35 @@
+package bjc.utils.data.lazy;
+
+/**
+ * Interface for some maintenance operations on lazy objects
+ *
+ * @author ben
+ *
+ */
+public interface ILazy {
+ /**
+ * Check if this object has been materialized
+ *
+ * @return Whether or not this object has been materialized
+ */
+ public boolean isMaterialized();
+
+ /**
+ * Check if there are pending actions that need to be applied
+ *
+ * @return Whether or not there are pending actions
+ */
+ public boolean hasPendingActions();
+
+ /**
+ * Make this object materialize itelf
+ */
+ public void materialize();
+
+ /**
+ * Make this object apply any pending objects
+ *
+ * As a requirement, will materialize the object if it is not materialized
+ */
+ public void applyPendingActions();
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java
index e74ce91..61a5956 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyHolder.java
@@ -19,7 +19,7 @@ import bjc.utils.funcdata.FunctionalList;
* @param <T>
* The type of the data being held
*/
-public class LazyHolder<T> implements IHolder<T> {
+public class LazyHolder<T> implements IHolder<T>, ILazy {
private final class LazyHolderSupplier<NewT>
implements Supplier<NewT> {
private FunctionalList<Function<T, T>> pendingActions;
@@ -70,8 +70,11 @@ public class LazyHolder<T> implements IHolder<T> {
* The supplier for a value when it is neededs
*/
public LazyHolder(Supplier<T> source) {
- heldSource = source;
+ if (source == null) {
+ throw new NullPointerException("Source must be non-null");
+ }
+ heldSource = source;
heldValue = null;
}
@@ -87,6 +90,10 @@ public class LazyHolder<T> implements IHolder<T> {
@Override
public void doWith(Consumer<T> action) {
+ if (action == null) {
+ throw new NullPointerException("Action must be non-null");
+ }
+
transform((value) -> {
// Do the action with the value
action.accept(value);
@@ -98,6 +105,10 @@ public class LazyHolder<T> implements IHolder<T> {
@Override
public <NewT> IHolder<NewT> map(Function<T, NewT> transform) {
+ if (transform == null) {
+ throw new NullPointerException("Transform must be non-null");
+ }
+
// Don't actually map until we need to
return new LazyHolder<>(
new LazyHolderSupplier<>(actions, transform));
@@ -105,6 +116,10 @@ public class LazyHolder<T> implements IHolder<T> {
@Override
public IHolder<T> transform(Function<T, T> transform) {
+ if (transform == null) {
+ throw new NullPointerException("Transform must be non-null");
+ }
+
// Queue the transform until we need to apply it
actions.add(transform);
@@ -113,6 +128,10 @@ public class LazyHolder<T> implements IHolder<T> {
@Override
public <E> E unwrap(Function<T, E> unwrapper) {
+ if (unwrapper == null) {
+ throw new NullPointerException("Unwrapper must be null");
+ }
+
// Actualize ourselves
if (heldValue == null) {
heldValue = heldSource.get();
@@ -124,4 +143,36 @@ public class LazyHolder<T> implements IHolder<T> {
return unwrapper.apply(heldValue);
}
-}
+ @Override
+ public boolean isMaterialized() {
+ if (heldSource != null) {
+ // We're materialized if a value exists
+ return heldValue == null;
+ } else {
+ // We're materialized by default
+ return true;
+ }
+ }
+
+ @Override
+ public boolean hasPendingActions() {
+ return actions.isEmpty();
+ }
+
+ @Override
+ public void materialize() {
+ // Only materialize if we haven't already
+ if (!isMaterialized()) {
+ heldValue = heldSource.get();
+ }
+ }
+
+ @Override
+ public void applyPendingActions() {
+ materialize();
+
+ actions.forEach((action) -> {
+ heldValue = action.apply(heldValue);
+ });
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyPair.java b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyPair.java
index 3c21b56..e08c8fb 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyPair.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/data/lazy/LazyPair.java
@@ -21,11 +21,14 @@ import bjc.utils.data.Pair;
* @param <R>
* The type of value stored on the right side of the pair
*/
-public class LazyPair<L, R> implements IPair<L, R> {
+public class LazyPair<L, R> implements IPair<L, R>, ILazy {
/**
* The backing store for this pair
*/
- protected IHolder<IPair<L, R>> delegatePair;
+ protected IHolder<IPair<L, R>> delegatePair;
+
+ private boolean materialized = false;
+ private boolean pendingActions = false;
/**
* Create a new blank lazy pair
@@ -43,6 +46,8 @@ public class LazyPair<L, R> implements IPair<L, R> {
* The initial value for the right side of the pair
*/
public LazyPair(L leftValue, R rightValue) {
+ materialized = true;
+
delegatePair = new LazyHolder<>(new Pair<>(leftValue, rightValue));
}
@@ -56,6 +61,10 @@ public class LazyPair<L, R> implements IPair<L, R> {
*/
public LazyPair(Supplier<L> leftValueSource,
Supplier<R> rightValueSource) {
+ if (leftValueSource == null || rightValueSource == null) {
+ throw new NullPointerException("Sources must be non-null");
+ }
+
delegatePair = new LazyHolder<>(() -> {
return new Pair<>(leftValueSource.get(),
rightValueSource.get());
@@ -68,7 +77,11 @@ public class LazyPair<L, R> implements IPair<L, R> {
* @param delegate
* The internal delegate for the pair
*/
- private LazyPair(IHolder<IPair<L, R>> delegate) {
+ private LazyPair(IHolder<IPair<L, R>> delegate, boolean mater,
+ boolean pend) {
+ materialized = mater;
+ pendingActions = pend;
+
delegatePair = delegate;
}
@@ -81,10 +94,15 @@ public class LazyPair<L, R> implements IPair<L, R> {
@Override
public <L2, R2> IPair<L2, R2> apply(Function<L, L2> leftTransform,
Function<R, R2> rightTransform) {
- IHolder<IPair<L2, R2>> newPair = delegatePair
- .map((currentPair) -> currentPair.apply(leftTransform, rightTransform));
+ if (leftTransform == null || rightTransform == null) {
+ throw new NullPointerException("Transforms must be non-null");
+ }
- return new LazyPair<>(newPair);
+ IHolder<IPair<L2, R2>> newPair =
+ delegatePair.map((currentPair) -> currentPair
+ .apply(leftTransform, rightTransform));
+
+ return new LazyPair<>(newPair, materialized, true);
}
/*
@@ -94,6 +112,12 @@ public class LazyPair<L, R> implements IPair<L, R> {
*/
@Override
public void doWith(BiConsumer<L, R> action) {
+ if (action == null) {
+ throw new NullPointerException("Action must be non-null");
+ }
+
+ pendingActions = true;
+
delegatePair.doWith((currentPair) -> {
currentPair.doWith(action);
});
@@ -106,6 +130,43 @@ public class LazyPair<L, R> implements IPair<L, R> {
*/
@Override
public <E> E merge(BiFunction<L, R, E> merger) {
- return delegatePair.unwrap((currentPair) -> currentPair.merge(merger));
+ if (merger == null) {
+ throw new NullPointerException("Merger must be non-null");
+ }
+
+ materialized = true;
+ pendingActions = false;
+
+ return delegatePair
+ .unwrap((currentPair) -> currentPair.merge(merger));
+ }
+
+ @Override
+ public boolean isMaterialized() {
+ return materialized;
+ }
+
+ @Override
+ public boolean hasPendingActions() {
+ return pendingActions;
+ }
+
+ /*
+ * Note: Materializing will also apply all currently pending actions
+ */
+ @Override
+ public void materialize() {
+ merge((left, right) -> null);
+
+ materialized = true;
+ pendingActions = false;
+ }
+
+ @Override
+ public void applyPendingActions() {
+ merge((left, right) -> null);
+
+ materialized = true;
+ pendingActions = false;
}
-}
+} \ No newline at end of file
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 a260d78..ff02515 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalList.java
@@ -1,10 +1,10 @@
package bjc.utils.funcdata;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.Random;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@@ -16,6 +16,8 @@ import bjc.utils.data.GenHolder;
import bjc.utils.data.IHolder;
import bjc.utils.data.Pair;
+import java.util.ArrayList;
+
/**
* A wrapper over another list that provides eager functional operations
* over it. Differs from a stream in every way except for the fact that
@@ -62,6 +64,10 @@ public class FunctionalList<E> implements Cloneable {
* The source for a backing list
*/
public FunctionalList(FunctionalList<E> sourceList) {
+ if (sourceList == null) {
+ throw new NullPointerException("Source list must be non-null");
+ }
+
// Find out if this should make a copy of the source's wrapped list
// instead.
//
@@ -88,6 +94,11 @@ public class FunctionalList<E> implements Cloneable {
* The list to use as a backing list.
*/
public FunctionalList(List<E> backingList) {
+ if (backingList == null) {
+ throw new NullPointerException(
+ "Backing list must be non-null");
+ }
+
wrappedList = backingList;
}
@@ -112,6 +123,10 @@ public class FunctionalList<E> implements Cloneable {
* predicate.
*/
public boolean allMatch(Predicate<E> matchPredicate) {
+ if (matchPredicate == null) {
+ throw new NullPointerException("Predicate must be non-null");
+ }
+
for (E item : wrappedList) {
if (!matchPredicate.test(item)) {
// We've found a non-matching item
@@ -132,6 +147,10 @@ public class FunctionalList<E> implements Cloneable {
* predicate.
*/
public boolean anyMatch(Predicate<E> matchPredicate) {
+ if (matchPredicate == null) {
+ throw new NullPointerException("Predicate must be not null");
+ }
+
for (E item : wrappedList) {
if (matchPredicate.test(item)) {
// We've found a matching item
@@ -176,13 +195,20 @@ public class FunctionalList<E> implements Cloneable {
public <T, F> FunctionalList<F> combineWith(
FunctionalList<T> rightList,
BiFunction<E, T, F> itemCombiner) {
+ if (rightList == null) {
+ throw new NullPointerException(
+ "Target combine list must not be null");
+ } else if (itemCombiner == null) {
+ throw new NullPointerException("Combiner must not be null");
+ }
+
FunctionalList<F> returnedList = new FunctionalList<>();
// Get the iterator for the other list
Iterator<T> rightIterator = rightList.toIterable().iterator();
- for (Iterator<E> leftIterator = wrappedList
- .iterator(); leftIterator.hasNext()
+ for (Iterator<E> leftIterator =
+ wrappedList.iterator(); leftIterator.hasNext()
&& rightIterator.hasNext();) {
// Add the transformed items to the result list
E leftVal = leftIterator.next();
@@ -212,6 +238,11 @@ public class FunctionalList<E> implements Cloneable {
* @return The first element in this list.
*/
public E first() {
+ if (wrappedList.size() < 1) {
+ throw new NoSuchElementException(
+ "Attempted to get first element of empty list");
+ }
+
return wrappedList.get(0);
}
@@ -227,14 +258,23 @@ public class FunctionalList<E> implements Cloneable {
* @return A new list containing the flattened results of applying the
* provided function.
*/
- public <T> FunctionalList<T> flatMap(
- Function<E, FunctionalList<T>> elementExpander) {
- FunctionalList<T> returnedList = new FunctionalList<>(
- this.wrappedList.size());
+ public <T> FunctionalList<T>
+ flatMap(Function<E, FunctionalList<T>> elementExpander) {
+ if (elementExpander == null) {
+ throw new NullPointerException("Expander must not be null");
+ }
+
+ FunctionalList<T> returnedList =
+ new FunctionalList<>(this.wrappedList.size());
forEach(element -> {
- FunctionalList<T> expandedElement = elementExpander
- .apply(element);
+ FunctionalList<T> expandedElement =
+ elementExpander.apply(element);
+
+ if (expandedElement == null) {
+ throw new NullPointerException(
+ "Expander returned null list");
+ }
// Add each element to the returned list
expandedElement.forEach(returnedList::add);
@@ -250,6 +290,10 @@ public class FunctionalList<E> implements Cloneable {
* The action to apply to each member of the list.
*/
public void forEach(Consumer<E> action) {
+ if (action == null) {
+ throw new NullPointerException("Action is null");
+ }
+
wrappedList.forEach(action);
}
@@ -261,6 +305,10 @@ public class FunctionalList<E> implements Cloneable {
* index.
*/
public void forEachIndexed(BiConsumer<Integer, E> indexedAction) {
+ if (indexedAction == null) {
+ throw new NullPointerException("Action must not be null");
+ }
+
// This is held b/c ref'd variables must be final/effectively final
GenHolder<Integer> currentIndex = new GenHolder<>(0);
@@ -302,6 +350,10 @@ public class FunctionalList<E> implements Cloneable {
* @return A list containing all elements that match the predicate
*/
public FunctionalList<E> getMatching(Predicate<E> matchPredicate) {
+ if (matchPredicate == null) {
+ throw new NullPointerException("Predicate must not be null");
+ }
+
FunctionalList<E> returnedList = new FunctionalList<>();
wrappedList.forEach((element) -> {
@@ -344,8 +396,12 @@ public class FunctionalList<E> implements Cloneable {
* @return A new list containing the mapped elements of this list.
*/
public <T> FunctionalList<T> map(Function<E, T> elementTransformer) {
- FunctionalList<T> returnedList = new FunctionalList<>(
- this.wrappedList.size());
+ if (elementTransformer == null) {
+ throw new NullPointerException("Transformer must be not null");
+ }
+
+ FunctionalList<T> returnedList =
+ new FunctionalList<>(this.wrappedList.size());
forEach(element -> {
// Add the transformed item to the result
@@ -366,8 +422,8 @@ public class FunctionalList<E> implements Cloneable {
* @return A list containing pairs of this element and the specified
* list
*/
- public <T> FunctionalList<Pair<E, T>> pairWith(
- FunctionalList<T> rightList) {
+ public <T> FunctionalList<Pair<E, T>>
+ pairWith(FunctionalList<T> rightList) {
return combineWith(rightList, Pair<E, T>::new);
}
@@ -378,13 +434,21 @@ public class FunctionalList<E> implements Cloneable {
* The size of elements to put into each one of the sublists
* @return A list partitioned into partitions of size nPerPart
*/
- public FunctionalList<FunctionalList<E>> partition(
- int numberPerPartition) {
- FunctionalList<FunctionalList<E>> returnedList = new FunctionalList<>();
+ public FunctionalList<FunctionalList<E>>
+ partition(int numberPerPartition) {
+ if (numberPerPartition < 1
+ || numberPerPartition > wrappedList.size()) {
+ throw new IllegalArgumentException("" + numberPerPartition
+ + " is an invalid partition size. Must be between 1 and "
+ + wrappedList.size());
+ }
+
+ FunctionalList<FunctionalList<E>> returnedList =
+ new FunctionalList<>();
// The current partition being filled
- GenHolder<FunctionalList<E>> currentPartition = new GenHolder<>(
- new FunctionalList<>());
+ GenHolder<FunctionalList<E>> currentPartition =
+ new GenHolder<>(new FunctionalList<>());
this.forEach((element) -> {
if (isPartitionFull(numberPerPartition, currentPartition)) {
@@ -433,6 +497,11 @@ public class FunctionalList<E> implements Cloneable {
* @return A random element from this list.
*/
public E randItem(Random rnd) {
+ if (rnd == null) {
+ throw new NullPointerException(
+ "Random source must not be null");
+ }
+
int randomIndex = rnd.nextInt(wrappedList.size());
return wrappedList.get(randomIndex);
@@ -460,6 +529,12 @@ public class FunctionalList<E> implements Cloneable {
public <T, F> F reduceAux(T initialValue,
BiFunction<E, T, T> stateAccumulator,
Function<T, F> resultTransformer) {
+ if (stateAccumulator == null) {
+ throw new NullPointerException("Accumulator must not be null");
+ } else if (resultTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
// The current collapsed list
IHolder<T> currentState = new GenHolder<>(initialValue);
@@ -481,6 +556,10 @@ public class FunctionalList<E> implements Cloneable {
* @return Whether there was anything that satisfied the predicate
*/
public boolean removeIf(Predicate<E> removePredicate) {
+ if (removePredicate == null) {
+ throw new NullPointerException("Predicate must be non-null");
+ }
+
return wrappedList.removeIf(removePredicate);
}
@@ -502,7 +581,8 @@ public class FunctionalList<E> implements Cloneable {
* @param searchKey
* The key to search for.
* @param comparator
- * The way to compare elements for searching
+ * The way to compare elements for searching. Pass null to
+ * use the natural ordering for E
* @return The element if it is in this list, or null if it is not.
*/
public E search(E searchKey, Comparator<E> comparator) {
@@ -524,7 +604,8 @@ public class FunctionalList<E> implements Cloneable {
* elements. Does change the underlying list.
*
* @param comparator
- * The way to compare elements for sorting.
+ * The way to compare elements for sorting. Pass null to use
+ * E's natural ordering
*/
public void sort(Comparator<E> comparator) {
Collections.sort(wrappedList, comparator);
@@ -554,7 +635,7 @@ public class FunctionalList<E> implements Cloneable {
// Remove trailing space and comma
sb.deleteCharAt(sb.length() - 1);
- //sb.deleteCharAt(sb.length() - 2);
+ // sb.deleteCharAt(sb.length() - 2);
sb.append(")");
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java
new file mode 100644
index 0000000..0eb2e94
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalMap.java
@@ -0,0 +1,151 @@
+package bjc.utils.funcdata;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import bjc.utils.data.Pair;
+
+/**
+ * Functional wrapper over map providing some useful things
+ *
+ * @author ben
+ *
+ * @param <K>
+ * The type of this map's keys
+ * @param <V>
+ * The type of this map's values
+ *
+ */
+public class FunctionalMap<K, V> {
+ private final class TransformedMap<V2> extends FunctionalMap<K, V2> {
+ private FunctionalMap<K, V> mapToTransform;
+ private Function<V, V2> transformer;
+
+ public TransformedMap(FunctionalMap<K, V> destMap,
+ Function<V, V2> transform) {
+ mapToTransform = destMap;
+ transformer = transform;
+ }
+
+ @Override
+ public V2 get(K key) {
+ return transformer.apply(mapToTransform.get(key));
+ }
+ }
+
+ private Map<K, V> wrappedMap;
+
+ /**
+ * Create a new blank functional map
+ */
+ public FunctionalMap() {
+ wrappedMap = new HashMap<>();
+ }
+
+ /**
+ * Create a new functional map wrapping the specified map
+ *
+ * @param wrap
+ * The map to wrap
+ */
+ public FunctionalMap(Map<K, V> wrap) {
+ if (wrap == null) {
+ throw new NullPointerException("Map to wrap must not be null");
+ }
+
+ wrappedMap = wrap;
+ }
+
+ /**
+ * Create a new functional map with the specified entries
+ *
+ * @param entries
+ * The entries to put into the map
+ */
+ @SafeVarargs
+ public FunctionalMap(Pair<K, V>... entries) {
+ this();
+
+ for (Pair<K, V> entry : entries) {
+ entry.doWith((key, val) -> {
+ wrappedMap.put(key, val);
+ });
+ }
+ }
+
+ /**
+ * Add an entry to the map
+ *
+ * @param key
+ * The key to put the value under
+ * @param val
+ * The value to add
+ * @return The previous value of the key in the map, or null if the key
+ * wasn't in the map. However, note that it may also return
+ * null if the key was set to null.
+ *
+ */
+ public V put(K key, V val) {
+ if (key == null) {
+ throw new NullPointerException("Key must not be null");
+ }
+
+ return wrappedMap.put(key, val);
+ }
+
+ /**
+ * Get the value assigned to the given key
+ *
+ * @param key
+ * The key to look for a value under
+ * @return The value of the key
+ *
+ *
+ */
+ public V get(K key) {
+ if (key == null) {
+ throw new NullPointerException("Key must not be null");
+ }
+
+ if (wrappedMap.containsKey(wrappedMap)) {
+ return wrappedMap.get(key);
+ } else {
+ throw new IllegalArgumentException(
+ "Key " + key + " is not present in the map");
+ }
+ }
+
+ /**
+ * Transform the values returned by this map.
+ *
+ * NOTE: This transform is applied once for each lookup of a value, so
+ * the transform passed should be a proper function, or things will
+ * likely not work as expected.
+ *
+ * @param <V2>
+ * The new type of returned values
+ * @param transformer
+ * The function to use to transform values
+ * @return The map where each value will be transformed after lookup
+ */
+ public <V2> FunctionalMap<K, V2>
+ mapValues(Function<V, V2> transformer) {
+ if (transformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
+ return new TransformedMap<>(this, transformer);
+ }
+
+ /**
+ * Check if this map contains the specified key
+ *
+ * @param key
+ * The key to check
+ * @return Whether or not the map contains the key
+ */
+ public boolean containsKey(K key) {
+ return wrappedMap.containsKey(key);
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java
index 3c819cd..386b732 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/FunctionalStringTokenizer.java
@@ -19,6 +19,11 @@ public class FunctionalStringTokenizer {
* @return A new tokenizer that splits the provided string on spaces.
*/
public static FunctionalStringTokenizer fromString(String strang) {
+ if (strang == null) {
+ throw new NullPointerException(
+ "String to tokenize must be non-null");
+ }
+
return new FunctionalStringTokenizer(
new StringTokenizer(strang, " "));
}
@@ -35,6 +40,11 @@ public class FunctionalStringTokenizer {
* The string to tokenize
*/
public FunctionalStringTokenizer(String inp) {
+ if (inp == null) {
+ throw new NullPointerException(
+ "String to tokenize must be non-null");
+ }
+
this.input = new StringTokenizer(inp);
}
@@ -49,6 +59,14 @@ public class FunctionalStringTokenizer {
*/
public FunctionalStringTokenizer(String inputString,
String seperators) {
+ if (inputString == null) {
+ throw new NullPointerException(
+ "String to tokenize must not be null");
+ } else if (seperators == null) {
+ throw new NullPointerException(
+ "Tokens to split on must not be null");
+ }
+
this.input = new StringTokenizer(inputString, seperators);
}
@@ -59,6 +77,11 @@ public class FunctionalStringTokenizer {
* The non-functional string tokenizer to wrap
*/
public FunctionalStringTokenizer(StringTokenizer toWrap) {
+ if (toWrap == null) {
+ throw new NullPointerException(
+ "Wrapped tokenizer must not be null");
+ }
+
this.input = toWrap;
}
@@ -69,6 +92,10 @@ public class FunctionalStringTokenizer {
* The action to execute for each token
*/
public void forEachToken(Consumer<String> action) {
+ if (action == null) {
+ throw new NullPointerException("Action must not be null");
+ }
+
while (input.hasMoreTokens()) {
action.accept(input.nextToken());
}
@@ -84,7 +111,7 @@ public class FunctionalStringTokenizer {
}
/**
- * Return the next token from the tokenizer Returns null if no more
+ * Return the next token from the tokenizer. Returns null if no more
* tokens are available
*
* @return The next token from the tokenizer
@@ -110,13 +137,18 @@ public class FunctionalStringTokenizer {
* The function to use to convert tokens.
* @return A list containing all of the converted tokens.
*/
- public <E> FunctionalList<E> toList(Function<String, E> tokenTransformer) {
+ public <E> FunctionalList<E>
+ toList(Function<String, E> tokenTransformer) {
+ if (tokenTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
FunctionalList<E> returnList = new FunctionalList<>();
// Add each token to the list after transforming it
forEachToken(token -> {
E transformedToken = tokenTransformer.apply(token);
-
+
returnList.add(transformedToken);
});
@@ -124,6 +156,15 @@ public class FunctionalStringTokenizer {
}
/**
+ * Convert this tokenizer into a list of strings
+ *
+ * @return This tokenizer, converted into a list of strings
+ */
+ public FunctionalList<String> toList() {
+ return toList((String element) -> element);
+ }
+
+ /**
* Check if this tokenizer has more tokens
*
* @return Whether or not this tokenizer has more tokens
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java
index ec0e4df..fa92f85 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTree.java
@@ -39,6 +39,10 @@ public class BinarySearchTree<T> {
* The thing to use for comparing elements
*/
public BinarySearchTree(Comparator<T> cmp) {
+ if (cmp == null) {
+ throw new NullPointerException("Comparator must not be null");
+ }
+
elementCount = 0;
comparator = cmp;
}
@@ -169,6 +173,13 @@ public class BinarySearchTree<T> {
*/
public void traverse(TreeLinearizationMethod linearizationMethod,
Predicate<T> traversalPredicate) {
+ if (linearizationMethod == null) {
+ throw new NullPointerException(
+ "Linearization method must not be null");
+ } else if (traversalPredicate == null) {
+ throw new NullPointerException("Predicate must not be nulls");
+ }
+
rootElement.forEach(linearizationMethod, traversalPredicate);
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java
index 7e31328..d2f9013 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeLeaf.java
@@ -55,6 +55,10 @@ public class BinarySearchTreeLeaf<T> implements ITreePart<T> {
@Override
public <E> E collapse(Function<T, E> leafTransformer,
BiFunction<E, E, E> branchCollapser) {
+ if (leafTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
return leafTransformer.apply(data);
}
@@ -101,6 +105,10 @@ public class BinarySearchTreeLeaf<T> implements ITreePart<T> {
*/
@Override
public boolean directedWalk(DirectedWalkFunction<T> treeWalker) {
+ if (treeWalker == null) {
+ throw new NullPointerException("Tree walker must not be null");
+ }
+
switch (treeWalker.walk(data)) {
case SUCCESS:
return true;
@@ -119,6 +127,10 @@ public class BinarySearchTreeLeaf<T> implements ITreePart<T> {
@Override
public boolean forEach(TreeLinearizationMethod linearizationMethod,
Predicate<T> traversalPredicate) {
+ if (traversalPredicate == null) {
+ throw new NullPointerException("Predicate must not be null");
+ }
+
return traversalPredicate.test(data);
}
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java
index 77bb196..09a4912 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcdata/bst/BinarySearchTreeNode.java
@@ -51,6 +51,10 @@ public class BinarySearchTreeNode<T> extends BinarySearchTreeLeaf<T> {
*/
@Override
public void add(T element, Comparator<T> comparator) {
+ if (comparator == null) {
+ throw new NullPointerException("Comparator must not be null");
+ }
+
switch (comparator.compare(data, element)) {
case -1:
if (leftBranch == null) {
@@ -79,6 +83,10 @@ public class BinarySearchTreeNode<T> extends BinarySearchTreeLeaf<T> {
@Override
public <E> E collapse(Function<T, E> nodeCollapser,
BiFunction<E, E, E> branchCollapser) {
+ if (nodeCollapser == null || branchCollapser == null) {
+ throw new NullPointerException("Collapser must not be null");
+ }
+
E collapsedNode = nodeCollapser.apply(data);
if (leftBranch != null) {
@@ -112,6 +120,10 @@ public class BinarySearchTreeNode<T> extends BinarySearchTreeLeaf<T> {
@Override
public boolean contains(T element, Comparator<T> comparator) {
+ if (comparator == null) {
+ throw new NullPointerException("Comparator must not be null");
+ }
+
return directedWalk(currentElement -> {
switch (comparator.compare(element, currentElement)) {
case -1:
@@ -128,6 +140,10 @@ public class BinarySearchTreeNode<T> extends BinarySearchTreeLeaf<T> {
@Override
public void delete(T element, Comparator<T> comparator) {
+ if (comparator == null) {
+ throw new NullPointerException("Comparator must not be null");
+ }
+
directedWalk(currentElement -> {
switch (comparator.compare(data, element)) {
case -1:
@@ -145,6 +161,10 @@ public class BinarySearchTreeNode<T> extends BinarySearchTreeLeaf<T> {
@Override
public boolean directedWalk(DirectedWalkFunction<T> treeWalker) {
+ if (treeWalker == null) {
+ throw new NullPointerException("Walker must not be null");
+ }
+
switch (treeWalker.walk(data)) {
case SUCCESS:
return true;
@@ -162,6 +182,13 @@ public class BinarySearchTreeNode<T> extends BinarySearchTreeLeaf<T> {
@Override
public boolean forEach(TreeLinearizationMethod linearizationMethod,
Predicate<T> traversalPredicate) {
+ if (linearizationMethod == null) {
+ throw new NullPointerException(
+ "Linearization method must not be null");
+ } else if (traversalPredicate == null) {
+ throw new NullPointerException("Predicate must not be null");
+ }
+
switch (linearizationMethod) {
case PREORDER:
return preorderTraverse(linearizationMethod,
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 5215576..5eb488a 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java
@@ -28,16 +28,24 @@ public class ListUtils {
}
@Override
- public FunctionalList<String> apply(String opName,
- String opRegex) {
- if (StringUtils.containsOnly(token, opRegex)) {
+ public FunctionalList<String> 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(opName)) {
- return new FunctionalList<>(opName,
- token.split(opRegex)[1]);
- } else if (token.endsWith(opName)) {
- return new FunctionalList<>(token.split(opRegex)[0],
- opName);
+ } 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);
}
@@ -55,13 +63,22 @@ public class ListUtils {
@Override
public FunctionalList<String> 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);
} else {
- FunctionalList<String> splitTokens = new FunctionalList<>(
- tokenToSplit.split(operatorRegex));
+ FunctionalList<String> splitTokens =
+ new FunctionalList<>(
+ tokenToSplit.split(operatorRegex));
FunctionalList<String> result = new FunctionalList<>();
@@ -161,16 +178,29 @@ public class ListUtils {
public static <E> FunctionalList<FunctionalList<E>> groupPartition(
FunctionalList<E> input, Function<E, Integer> elementCounter,
int numberPerPartition) {
+ if (input == null) {
+ throw new NullPointerException("Input list must not be null");
+ } else if (elementCounter == null) {
+ throw new NullPointerException("Counter must not be null");
+ } else if (numberPerPartition < 1
+ || numberPerPartition > input.getSize()) {
+ throw new IllegalArgumentException(
+ "" + numberPerPartition + " is not a valid"
+ + " partition size. Must be between 1 and "
+ + input.getSize());
+ }
+
/*
* List that holds our results
*/
- FunctionalList<FunctionalList<E>> returnedList = new FunctionalList<>();
+ FunctionalList<FunctionalList<E>> returnedList =
+ new FunctionalList<>();
/*
* List that holds current partition
*/
- GenHolder<FunctionalList<E>> currentPartition = new GenHolder<>(
- new FunctionalList<>());
+ GenHolder<FunctionalList<E>> currentPartition =
+ new GenHolder<>(new FunctionalList<>());
/*
* List that holds elements rejected during current pass
*/
@@ -184,8 +214,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,
@@ -226,14 +258,22 @@ public class ListUtils {
public static FunctionalList<String> splitTokens(
FunctionalList<String> input,
Deque<Pair<String, String>> operators) {
- GenHolder<FunctionalList<String>> ret = new GenHolder<>(input);
+ if (input == null) {
+ throw new NullPointerException("Input must not be null");
+ } else if (operators == null) {
+ throw new NullPointerException(
+ "Set of operators must not be null");
+ }
+
+ GenHolder<FunctionalList<String>> returnedList =
+ new GenHolder<>(input);
- operators.forEach(
- (op) -> ret.transform((oldRet) -> oldRet.flatMap((tok) -> {
- return op.merge(new TokenSplitter(tok));
+ operators.forEach((operator) -> returnedList
+ .transform((oldReturn) -> oldReturn.flatMap((token) -> {
+ return operator.merge(new TokenSplitter(token));
})));
- return ret.unwrap((list) -> list);
+ return returnedList.unwrap((list) -> list);
}
/**
@@ -241,20 +281,27 @@ public class ListUtils {
*
* @param input
* The tokens to deaffix
- * @param ops
+ * @param operators
* The affixes to remove
* @return The tokens that have been deaffixed
*
*/
public static FunctionalList<String> deAffixTokens(
FunctionalList<String> input,
- Deque<Pair<String, String>> ops) {
- GenHolder<FunctionalList<String>> returnedList = new GenHolder<>(
- input);
+ Deque<Pair<String, String>> operators) {
+ if (input == null) {
+ throw new NullPointerException("Input must not be null");
+ } else if (operators == null) {
+ throw new NullPointerException(
+ "Set of operators must not be null");
+ }
+
+ GenHolder<FunctionalList<String>> returnedList =
+ new GenHolder<>(input);
- ops.forEach((op) -> returnedList
- .transform((oldRet) -> oldRet.flatMap((tok) -> {
- return op.merge(new TokenDeaffixer(tok));
+ operators.forEach((operator) -> returnedList
+ .transform((oldReturn) -> oldReturn.flatMap((token) -> {
+ return operator.merge(new TokenDeaffixer(token));
})));
return returnedList.unwrap((list) -> list);
@@ -269,6 +316,10 @@ public class ListUtils {
* @return The collapsed string of tokens
*/
public static String collapseTokens(FunctionalList<String> input) {
+ if (input == null) {
+ throw new NullPointerException("Input must not be null");
+ }
+
return collapseTokens(input, "");
}
@@ -278,23 +329,29 @@ public class ListUtils {
*
* @param input
* The list of tokens to collapse
- * @param sep
+ * @param seperator
* The seperator to use for seperating tokens
* @return The collapsed string of tokens
*/
public static String collapseTokens(FunctionalList<String> input,
- String sep) {
+ String seperator) {
+ if (input == null) {
+ throw new NullPointerException("Input must not be null");
+ } else if (seperator == null) {
+ throw new NullPointerException("Seperator must not be null");
+ }
+
if (input.getSize() < 1) {
return "";
} else if (input.getSize() == 1) {
return input.first();
} else {
- return input.reduceAux("",
- (currentString, state) -> state + currentString + sep,
- (strang) -> {
- return strang.substring(0,
- strang.length() - sep.length());
- });
+ return input.reduceAux("", (currentString, state) -> {
+ return state + currentString + seperator;
+ }, (strang) -> {
+ return strang.substring(0,
+ strang.length() - seperator.length());
+ });
}
}
} \ 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 b7d20aa..a73292c 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/StringUtils.java
@@ -28,6 +28,12 @@ public class StringUtils {
* group is then matched one or more times and the pattern matches
* to the end of the string
*/
+ if (input == null) {
+ throw new NullPointerException("Input must not be null");
+ } else if (regex == null) {
+ throw new NullPointerException("Regex must not be null");
+ }
+
return input.matches("\\A(?:" + regex + ")+\\Z");
}
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 ca0578d..4f194f3 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/RandomGrammar.java
@@ -62,6 +62,10 @@ public class RandomGrammar<E> extends WeightedGrammar<E> {
* The cases to add for this rule.
*/
public void makeRule(E rule, FunctionalList<FunctionalList<E>> cases) {
+ if (cases == null) {
+ throw new NullPointerException("Cases must not be null");
+ }
+
super.addRule(rule);
cases.forEach(currentCase -> super.addCase(rule, 1, currentCase));
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 28b61c5..cdfe056 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedGrammar.java
@@ -57,21 +57,33 @@ public class WeightedGrammar<E> {
public WeightedGrammar(Random source) {
this();
+ if (source == null) {
+ throw new NullPointerException(
+ "Source of randomness must be non-null");
+ }
+
rng = source;
}
/**
* Add a case to an already existing rule.
*
- * @param rule
+ * @param ruleName
* The rule to add a case to.
* @param probability
* The probability for this rule to be chosen.
* @param cse
* The case being added.
*/
- public void addCase(E rule, int probability, FunctionalList<E> cse) {
- rules.get(rule).addProbability(probability, cse);
+ public void addCase(E ruleName, int probability,
+ FunctionalList<E> cse) {
+ if (ruleName == null) {
+ throw new NullPointerException("Rule name must be not null");
+ } else if (cse == null) {
+ throw new NullPointerException("Case body must not be null");
+ }
+
+ rules.get(ruleName).addProbability(probability, cse);
}
/**
@@ -84,6 +96,14 @@ public class WeightedGrammar<E> {
* @return Whether the alias was succesfully created
*/
public boolean addGrammarAlias(E name, E alias) {
+ if (name == null) {
+ throw new NullPointerException(
+ "Subgrammar name must not be null");
+ } else if (alias == null) {
+ throw new NullPointerException(
+ "Subgrammar alias must not be null");
+ }
+
if (subgrammars.containsKey(alias)) {
return false;
} else {
@@ -107,6 +127,11 @@ public class WeightedGrammar<E> {
if (rng == null) {
rng = new Random();
}
+
+ if (name == null) {
+ throw new NullPointerException("Rule name must not be null");
+ }
+
return addRule(name, new WeightedRandom<>(rng));
}
@@ -121,6 +146,12 @@ public class WeightedGrammar<E> {
*/
public boolean addRule(E name,
WeightedRandom<FunctionalList<E>> cases) {
+ if (name == null) {
+ throw new NullPointerException("Name must not be null");
+ } else if (cases == null) {
+ throw new NullPointerException("Cases must not be null");
+ }
+
if (rules.containsKey(name)) {
return false;
} else {
@@ -139,6 +170,13 @@ public class WeightedGrammar<E> {
* @return Whether or not the subgrammar was succesfully added.
*/
public boolean addSubgrammar(E name, WeightedGrammar<E> subgrammar) {
+ if (name == null) {
+ throw new NullPointerException(
+ "Subgrammar name must not be null");
+ } else if (subgrammar == null) {
+ throw new NullPointerException("Subgrammar must not be null");
+ }
+
if (subgrammars.containsKey(name)) {
return false;
} else {
@@ -157,6 +195,10 @@ public class WeightedGrammar<E> {
*/
public FunctionalList<FunctionalList<E>>
generateDebugValues(E ruleName) {
+ if (ruleName == null) {
+ throw new NullPointerException("Rule name must not be null");
+ }
+
FunctionalList<FunctionalList<E>> returnedList =
new FunctionalList<>();
@@ -187,6 +229,15 @@ public class WeightedGrammar<E> {
*/
public <T> FunctionalList<T> generateGenericValues(E initRule,
Function<E, T> tokenTransformer, T spacer) {
+ if (initRule == null) {
+ throw new NullPointerException(
+ "Initial rule must not be null");
+ } else if (tokenTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ } else if (spacer == null) {
+ throw new NullPointerException("Spacer must not be null");
+ }
+
FunctionalList<T> returnedList = new FunctionalList<>();
if (subgrammars.containsKey(initRule)) {
@@ -205,7 +256,14 @@ public class WeightedGrammar<E> {
returnedList.add(spacer);
}));
} else {
- returnedList.add(tokenTransformer.apply(initRule));
+ T transformedToken = tokenTransformer.apply(initRule);
+
+ if (transformedToken == null) {
+ throw new NullPointerException(
+ "Transformer created null token");
+ }
+
+ returnedList.add(transformedToken);
returnedList.add(spacer);
}
@@ -244,6 +302,11 @@ public class WeightedGrammar<E> {
* @return The subgrammar with the specified name.
*/
public WeightedGrammar<E> getSubgrammar(E name) {
+ if (name == null) {
+ throw new NullPointerException(
+ "Subgrammar name must not be null");
+ }
+
return subgrammars.get(name);
}
@@ -270,6 +333,16 @@ public class WeightedGrammar<E> {
*/
public void multiPrefixRule(E ruleName, E prefixToken,
int additionalProbability, int numberOfTimes) {
+ if (ruleName == null) {
+ throw new NullPointerException("Rule name must not be null");
+ } else if (prefixToken == null) {
+ throw new NullPointerException(
+ "Prefix token must not be null");
+ } else if (numberOfTimes < 1) {
+ throw new IllegalArgumentException(
+ "Number of times to prefix must be positive.");
+ }
+
WeightedRandom<FunctionalList<E>> rule = rules.get(ruleName);
FunctionalList<Pair<Integer, FunctionalList<E>>> newResults =
@@ -315,6 +388,13 @@ public class WeightedGrammar<E> {
*/
public void prefixRule(E ruleName, E prefixToken,
int additionalProbability) {
+ if (ruleName == null) {
+ throw new NullPointerException("Rule name must not be null");
+ } else if (prefixToken == null) {
+ throw new NullPointerException(
+ "Prefix token must not be null");
+ }
+
WeightedRandom<FunctionalList<E>> rule = rules.get(ruleName);
FunctionalList<Pair<Integer, FunctionalList<E>>> newResults =
@@ -340,6 +420,10 @@ public class WeightedGrammar<E> {
* The name of the rule to remove.
*/
public void deleteRule(E name) {
+ if (name == null) {
+ throw new NullPointerException("Rule name must not be null");
+ }
+
rules.remove(name);
}
@@ -350,6 +434,10 @@ public class WeightedGrammar<E> {
* The name of the subgrammar to remove.
*/
public void deleteSubgrammar(E name) {
+ if (name == null) {
+ throw new NullPointerException("Rule name must not be null");
+ }
+
subgrammars.remove(name);
}
@@ -386,13 +474,20 @@ public class WeightedGrammar<E> {
*
* @param ruleName
* The rule to suffix
- * @param prefixToken
+ * @param suffixToken
* The token to prefix to the rule
* @param additionalProbability
* Additional probability of the prefixed rule
*/
- public void suffixRule(E ruleName, E prefixToken,
+ public void suffixRule(E ruleName, E suffixToken,
int additionalProbability) {
+ if (ruleName == null) {
+ throw new NullPointerException("Rule name must not be null");
+ } else if (suffixToken == null) {
+ throw new NullPointerException(
+ "Prefix token must not be null");
+ }
+
WeightedRandom<FunctionalList<E>> rule = rules.get(ruleName);
FunctionalList<Pair<Integer, FunctionalList<E>>> newResults =
@@ -401,7 +496,7 @@ public class WeightedGrammar<E> {
rule.getValues().forEach((par) -> {
FunctionalList<E> newCase =
par.merge((left, right) -> right.clone());
- newCase.add(prefixToken);
+ newCase.add(suffixToken);
newResults.add(new Pair<>(par.merge((left, right) -> left)
+ additionalProbability, newCase));
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 5a8ef8f..5157ee2 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gen/WeightedRandom.java
@@ -44,6 +44,11 @@ public class WeightedRandom<E> {
probabilities = new FunctionalList<>();
results = new FunctionalList<>();
+ if (src == null) {
+ throw new NullPointerException(
+ "Source of randomness must not be null");
+ }
+
source = src;
}
@@ -109,4 +114,4 @@ public class WeightedRandom<E> {
public FunctionalList<Pair<Integer, E>> getValues() {
return probabilities.pairWith(results);
}
-}
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java
index 513044e..e583210 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/AdjacencyMap.java
@@ -5,6 +5,7 @@ import java.io.OutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.InputMismatchException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
@@ -30,36 +31,79 @@ public class AdjacencyMap<T> {
* @return An adjacency map defined by the text
*/
public static AdjacencyMap<Integer> fromStream(InputStream stream) {
- Scanner inputSource = new Scanner(stream);
- inputSource.useDelimiter("\n");
-
- // First, read in number of vertices
- int numVertices = Integer.parseInt(inputSource.next());
-
- Set<Integer> vertices = new HashSet<>();
- IntStream.range(0, numVertices)
- .forEach(element -> vertices.add(element));
+ if (stream == null) {
+ throw new NullPointerException(
+ "Input source must not be null");
+ }
// Create the adjacency map
- AdjacencyMap<Integer> adjacencyMap = new AdjacencyMap<>(vertices);
+ AdjacencyMap<Integer> adjacencyMap;
- GenHolder<Integer> row = new GenHolder<>(0);
+ try (Scanner inputSource = new Scanner(stream)) {
+ inputSource.useDelimiter("\n");
- inputSource.forEachRemaining((strang) -> {
- String[] parts = strang.split(" ");
- int column = 0;
+ int numVertices;
- for (String part : parts) {
- adjacencyMap.setWeight(row.unwrap(number -> number),
- column, Integer.parseInt(part));
+ String possibleVertices = inputSource.next();
- column++;
+ try {
+ // First, read in number of vertices
+ numVertices = Integer.parseInt(possibleVertices);
+ } catch (NumberFormatException nfex) {
+ throw new InputMismatchException(
+ "The first line must contain the number of vertices. "
+ + possibleVertices
+ + " is not a valid number");
}
- row.transform((number) -> number + 1);
- });
+ if (numVertices <= 0) {
+ throw new InputMismatchException(
+ "The number of vertices must be greater than 0");
+ }
+
+ Set<Integer> vertices = new HashSet<>();
+
+ IntStream.range(0, numVertices)
+ .forEach(element -> vertices.add(element));
+
+ adjacencyMap = new AdjacencyMap<>(vertices);
+
+ GenHolder<Integer> row = new GenHolder<>(0);
+
+ inputSource.forEachRemaining((strang) -> {
+ String[] parts = strang.split(" ");
+
+ if (parts.length != numVertices) {
+ throw new InputMismatchException(
+ "Must specify a weight for all " + numVertices
+ + " vertices");
+ }
+
+ int column = 0;
- inputSource.close();
+ for (String part : parts) {
+ int columnWeight;
+
+ try {
+ columnWeight = Integer.parseInt(part);
+ } catch (NumberFormatException nfex) {
+ throw new InputMismatchException(
+ "" + part + " is not a valid weight.");
+ }
+
+ adjacencyMap.setWeight(row.unwrap(number -> number),
+ column, columnWeight);
+
+ column++;
+ }
+
+ row.transform((number) -> {
+ int newNumber = number + 1;
+
+ return newNumber;
+ });
+ });
+ }
return adjacencyMap;
}
@@ -76,6 +120,10 @@ public class AdjacencyMap<T> {
* The set of vertices to create a map from
*/
public AdjacencyMap(Set<T> vertices) {
+ if (vertices == null) {
+ throw new NullPointerException("Vertices must not be null");
+ }
+
vertices.forEach(vertex -> {
Map<T, Integer> vertexRow = new HashMap<>();
@@ -97,6 +145,7 @@ public class AdjacencyMap<T> {
adjacencyMap.entrySet().forEach(mapEntry -> {
Set<Entry<T, Integer>> entryVertices =
mapEntry.getValue().entrySet();
+
entryVertices.forEach(targetVertex -> {
int leftValue = targetVertex.getValue();
int rightValue = adjacencyMap.get(targetVertex.getKey())
@@ -122,6 +171,22 @@ public class AdjacencyMap<T> {
* The weight of the edge
*/
public void setWeight(T sourceVertex, T targetVertex, int edgeWeight) {
+ if (sourceVertex == null) {
+ throw new NullPointerException(
+ "Source vertex must not be null");
+ } else if (targetVertex == null) {
+ throw new NullPointerException(
+ "Target vertex must not be null");
+ }
+
+ if (!adjacencyMap.containsKey(sourceVertex)) {
+ throw new IllegalArgumentException("Source vertex "
+ + sourceVertex + " isn't present in map");
+ } else if (!adjacencyMap.containsKey(targetVertex)) {
+ throw new IllegalArgumentException("Target vertex "
+ + targetVertex + " isn't present in map");
+ }
+
adjacencyMap.get(sourceVertex).put(targetVertex, edgeWeight);
}
@@ -145,11 +210,16 @@ public class AdjacencyMap<T> {
/**
* Convert an adjacency map back into a stream
*
- * @param outputSource
+ * @param outputSink
* The stream to convert to
*/
- public void toStream(OutputStream outputSource) {
- PrintStream outputPrinter = new PrintStream(outputSource);
+ public void toStream(OutputStream outputSink) {
+ if (outputSink == null) {
+ throw new NullPointerException(
+ "Output source must not be null");
+ }
+
+ PrintStream outputPrinter = new PrintStream(outputSink);
adjacencyMap.entrySet().forEach(sourceVertex -> {
sourceVertex.getValue().entrySet()
diff --git a/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java b/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java
index 44aa8e7..58a233a 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/Edge.java
@@ -30,6 +30,14 @@ public class Edge<T> {
* The distance between initial and terminal edge
*/
public Edge(T initialNode, T terminalNode, int distance) {
+ if (initialNode == null) {
+ throw new NullPointerException(
+ "Initial node must not be null");
+ } else if (terminalNode == null) {
+ throw new NullPointerException(
+ "Terminal node must not be null");
+ }
+
this.source = initialNode;
this.target = terminalNode;
this.distance = distance;
@@ -68,4 +76,58 @@ public class Edge<T> {
return " first vertex " + source + " to vertex " + target
+ " with distance: " + distance;
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + distance;
+ result = prime * result
+ + ((source == null) ? 0 : source.hashCode());
+ result = prime * result
+ + ((target == null) ? 0 : target.hashCode());
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ } else if (obj == null) {
+ return false;
+ } else if (getClass() != obj.getClass()) {
+ return false;
+ } else {
+
+ Edge<?> other = (Edge<?>) obj;
+
+ if (distance != other.distance) {
+ return false;
+ } else if (source == null) {
+ if (other.source != null) {
+ return false;
+ }
+ } else if (!source.equals(other.source)) {
+ return false;
+ } else if (target == null) {
+ if (other.target != null) {
+ return false;
+ }
+ } else if (!target.equals(other.target)) {
+ return false;
+ }
+
+ return true;
+ }
+ }
}
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 5172df5..f6bfc85 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/graph/Graph.java
@@ -53,9 +53,7 @@ public class Graph<T> {
if (sourceVertex == null) {
throw new NullPointerException(
"The source vertex cannot be null");
- }
-
- if (targetVertex == null) {
+ } else if (targetVertex == null) {
throw new NullPointerException(
"The target vertex cannot be null");
}
@@ -79,19 +77,25 @@ public class Graph<T> {
* Execute an action for all edges of a specific vertex matching
* conditions
*
- * @param source
+ * @param sourceVertex
* The vertex to test edges for
* @param edgeMatcher
* The conditions an edge must match
* @param edgeAction
* The action to execute for matching edges
*/
- public void forAllEdgesMatchingAt(T source,
+ public void forAllEdgesMatchingAt(T sourceVertex,
BiPredicate<T, Integer> edgeMatcher,
BiConsumer<T, Integer> edgeAction) {
- getEdges(source).forEach((tgt, weight) -> {
- if (edgeMatcher.test(tgt, weight)) {
- edgeAction.accept(tgt, weight);
+ if (edgeMatcher == null) {
+ throw new NullPointerException("Matcher must not be null");
+ } else if (edgeAction == null) {
+ throw new NullPointerException("Action must not be null");
+ }
+
+ getEdges(sourceVertex).forEach((targetVertex, vertexWeight) -> {
+ if (edgeMatcher.test(targetVertex, vertexWeight)) {
+ edgeAction.accept(targetVertex, vertexWeight);
}
});
}
@@ -107,6 +111,9 @@ public class Graph<T> {
// Can't find edges for a null source
if (source == null) {
throw new NullPointerException("The source cannot be null.");
+ } else if (!backingGraph.containsKey(source)) {
+ throw new IllegalArgumentException(
+ "Vertex " + source + " is not in graph");
}
return Collections.unmodifiableMap(backingGraph.get(source));
@@ -213,8 +220,7 @@ public class Graph<T> {
if (sourceVertex == null) {
throw new NullPointerException(
"The source vertex cannot be null");
- }
- if (targetVertex == null) {
+ } else if (targetVertex == null) {
throw new NullPointerException(
"The target vertex cannot be null");
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java b/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java
index be1746f..e563530 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/ExtensionFileFilter.java
@@ -49,6 +49,10 @@ public class ExtensionFileFilter extends FileFilter {
@Override
public boolean accept(File pathname) {
+ if (pathname == null) {
+ throw new NullPointerException("Pathname must not be null");
+ }
+
return extensions.anyMatch(pathname.getName()::endsWith);
}
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 42c5761..4bbe6e7 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/ListParameterPanel.java
@@ -68,24 +68,60 @@ public class ListParameterPanel<E> extends JPanel {
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JPanel buttonPanel = new JPanel();
- buttonPanel.setLayout(new HLayout(3));
-
- JButton addParam = new JButton("Add...");
- JButton editParam = new JButton("Edit...");
- JButton removeParam = new JButton("Remove...");
-
- addParam.addActionListener(
- (event) -> ((DefaultListModel<E>) list.getModel())
- .addElement(addAction.get()));
- editParam.addActionListener(
- (event) -> editAction.accept(list.getSelectedValue()));
- removeParam.addActionListener((event) -> removeAction
- .accept(((DefaultListModel<E>) list.getModel())
- .remove(list.getSelectedIndex())));
-
- buttonPanel.add(addParam);
- buttonPanel.add(editParam);
- buttonPanel.add(removeParam);
+
+ int numButtons = 0;
+
+ if (addAction != null) {
+ numButtons++;
+ }
+
+ if (editAction != null) {
+ numButtons++;
+ }
+
+ if (removeAction != null) {
+ numButtons++;
+ }
+
+ buttonPanel.setLayout(new HLayout(numButtons));
+
+ JButton addParam = null;
+
+ if (addAction != null) {
+ addParam = new JButton("Add...");
+ addParam.addActionListener(
+ (event) -> ((DefaultListModel<E>) list.getModel())
+ .addElement(addAction.get()));
+ }
+
+ JButton editParam = null;
+
+ if (editAction != null) {
+ editParam = new JButton("Edit...");
+ editParam.addActionListener(
+ (event) -> editAction.accept(list.getSelectedValue()));
+ }
+
+ JButton removeParam = null;
+
+ if (removeAction != null) {
+ removeParam = new JButton("Remove...");
+ removeParam.addActionListener((event) -> removeAction
+ .accept(((DefaultListModel<E>) list.getModel())
+ .remove(list.getSelectedIndex())));
+ }
+
+ if (addAction != null) {
+ buttonPanel.add(addParam);
+ }
+
+ if (editAction != null) {
+ buttonPanel.add(editParam);
+ }
+
+ if (removeAction != null) {
+ buttonPanel.add(removeParam);
+ }
add(list);
add(buttonPanel);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java
index fd7d05a..b09fbd8 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleDialogs.java
@@ -38,9 +38,10 @@ public class SimpleDialogs {
*/
public static int getBoundedInt(Component parent, String title,
String prompt, int lowerBound, int upperBound) {
- return getValue(parent, title, prompt, strang -> {
+ return getValue(parent, title, prompt, (strang) -> {
try {
int value = Integer.parseInt(strang);
+
return (value < upperBound) && (value > lowerBound);
} catch (NumberFormatException nfe) {
return false;
@@ -67,6 +68,15 @@ public class SimpleDialogs {
@SuppressWarnings("unchecked")
public static <E> E getChoice(Frame parent, String title,
String question, E... choices) {
+
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ } else if (question == null) {
+ throw new NullPointerException("Question must not be null");
+ }
+
JDialog mainDialog = new JDialog(parent, title, true);
mainDialog.setLayout(new VLayout(2));
@@ -134,6 +144,14 @@ public class SimpleDialogs {
*/
public static String getString(Component parent, String title,
String prompt) {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ } else if (prompt == null) {
+ throw new NullPointerException("Prompt must not be null");
+ }
+
return JOptionPane.showInputDialog(parent, prompt, title,
JOptionPane.QUESTION_MESSAGE);
}
@@ -159,6 +177,12 @@ public class SimpleDialogs {
public static <E> E getValue(Component parent, String title,
String prompt, Predicate<String> inputValidator,
Function<String, E> inputTransformer) {
+ if (inputValidator == null) {
+ throw new NullPointerException("Validator must not be null");
+ } else if (inputTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
String inputString = getString(parent, title, prompt);
while (!inputValidator.test(inputString)) {
@@ -199,6 +223,14 @@ public class SimpleDialogs {
*/
public static boolean getYesNo(Component parent, String title,
String question) {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ } else if (question == null) {
+ throw new NullPointerException("Question must not be null");
+ }
+
int dialogResult = JOptionPane.showConfirmDialog(parent, question,
title, JOptionPane.YES_NO_OPTION);
@@ -217,6 +249,15 @@ public class SimpleDialogs {
*/
public static void showError(Component parent, String title,
String errorMessage) {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ } else if (errorMessage == null) {
+ throw new NullPointerException(
+ "Error message must not be null");
+ }
+
JOptionPane.showMessageDialog(parent, errorMessage, title,
JOptionPane.ERROR_MESSAGE);
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleFileChooser.java b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleFileChooser.java
index 9648762..f39ff7c 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleFileChooser.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleFileChooser.java
@@ -18,6 +18,10 @@ import bjc.utils.exceptions.FileNotChosenException;
public class SimpleFileChooser {
private static File doOpenFile(Component parent, String title,
JFileChooser files) {
+ if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ }
+
files.setDialogTitle(title);
boolean success = false;
@@ -38,6 +42,10 @@ public class SimpleFileChooser {
private static File doSaveFile(Component parent, String title,
JFileChooser files) {
+ if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ }
+
files.setDialogTitle(title);
boolean success = false;
@@ -87,6 +95,7 @@ public class SimpleFileChooser {
public static File getOpenFile(Component parent, String title,
String... extensions) {
JFileChooser files = new JFileChooser();
+
files.addChoosableFileFilter(new ExtensionFileFilter(extensions));
return doOpenFile(parent, title, files);
@@ -121,6 +130,7 @@ public class SimpleFileChooser {
public static File getSaveFile(Component parent, String title,
String... extensions) {
JFileChooser files = new JFileChooser();
+
files.addChoosableFileFilter(new ExtensionFileFilter(extensions));
return doSaveFile(parent, title, files);
@@ -128,6 +138,13 @@ public class SimpleFileChooser {
private static void maybeDoOpenFile(Component parent,
JFileChooser files) throws FileNotChosenException {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (files == null) {
+ throw new NullPointerException(
+ "File chooser must not be null");
+ }
+
int dialogResult = files.showSaveDialog(parent);
if (dialogResult != JFileChooser.APPROVE_OPTION) {
@@ -137,6 +154,13 @@ public class SimpleFileChooser {
private static void maybeDoSaveFile(Component parent,
JFileChooser files) throws FileNotChosenException {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (files == null) {
+ throw new NullPointerException(
+ "File chooser must not be null");
+ }
+
int dialogResult = files.showSaveDialog(parent);
if (dialogResult != JFileChooser.APPROVE_OPTION) {
@@ -154,6 +178,10 @@ public class SimpleFileChooser {
* @return The file if the user chose one or null if they didn't.
*/
public static File maybeOpenFile(Component parent, String title) {
+ if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ }
+
JFileChooser files = new JFileChooser();
files.setDialogTitle(title);
@@ -175,6 +203,10 @@ public class SimpleFileChooser {
* @return The file if the user chose one or null if they didn't.
*/
public static File maybeSaveFile(Component parent, String title) {
+ if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ }
+
JFileChooser files = new JFileChooser();
files.setDialogTitle(title);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java
index 4695318..4db5027 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleJList.java
@@ -22,6 +22,10 @@ public class SimpleJList {
* @return A JList populated with the elements from ls.
*/
public static <E> JList<E> buildFromList(Iterable<E> listSource) {
+ if (listSource == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+
return new JList<>(buildModel(listSource));
}
@@ -36,6 +40,10 @@ public class SimpleJList {
* @return A list model populated with the elements from ls.
*/
public static <E> ListModel<E> buildModel(Iterable<E> listSource) {
+ if (listSource == null) {
+ throw new NullPointerException("Source must not be null");
+ }
+
DefaultListModel<E> defaultModel = new DefaultListModel<>();
listSource.forEach(defaultModel::addElement);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleTitledBorder.java b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleTitledBorder.java
index ddf5492..e2fd390 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleTitledBorder.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/SimpleTitledBorder.java
@@ -22,5 +22,4 @@ public class SimpleTitledBorder extends TitledBorder {
public SimpleTitledBorder(String title) {
super(new EtchedBorder(), title);
}
-
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java
index 368f8be..7e2c2d2 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/ExtensionFileFilter.java
@@ -29,6 +29,10 @@ public class ExtensionFileFilter implements FilenameFilter {
* The extensions to show in this filter.
*/
public ExtensionFileFilter(List<String> exts) {
+ if (exts == null) {
+ throw new NullPointerException("Extensions must not be null");
+ }
+
extensions = new FunctionalList<>(exts);
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java
index a8df3b9..7617199 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/gui/awt/SimpleFileDialog.java
@@ -42,6 +42,12 @@ public class SimpleFileDialog {
*/
public static File getOpenFile(Frame parent, String title,
String... extensions) {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ }
+
FileDialog fileDialog =
new FileDialog(parent, title, FileDialog.LOAD);
@@ -87,6 +93,12 @@ public class SimpleFileDialog {
*/
public static File getSaveFile(Frame parent, String title,
String... extensions) {
+ if (parent == null) {
+ throw new NullPointerException("Parent must not be null");
+ } else if (title == null) {
+ throw new NullPointerException("Title must not be null");
+ }
+
FileDialog fileDialog =
new FileDialog(parent, title, FileDialog.SAVE);
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java
index 4bfb469..d5ae3f2 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/AST.java
@@ -17,11 +17,26 @@ import bjc.utils.funcdata.bst.ITreePart.TreeLinearizationMethod;
* The type of token in this AST
*/
public class AST<T> {
- private T token;
+ /**
+ * Indent a string n levels
+ *
+ * @param builder
+ * The string to indent
+ * @param levels
+ * The number of levels to indent
+ */
+ protected static void indentNLevels(StringBuilder builder,
+ int levels) {
+ for (int i = 0; i <= levels; i++) {
+ builder.append("\t");
+ }
+ }
private AST<T> left;
private AST<T> right;
+ private T token;
+
/**
* Create a new leaf AST node
*
@@ -53,43 +68,6 @@ public class AST<T> {
}
/**
- * Traverse an AST
- *
- * @param linearizationMethod
- * The way to traverse the tree
- * @param action
- * The function to call on each traversed element
- */
- public void traverse(TreeLinearizationMethod linearizationMethod,
- Consumer<T> action) {
- if (left != null && right != null) {
- switch (linearizationMethod) {
- case INORDER:
- left.traverse(linearizationMethod, action);
- action.accept(token);
- right.traverse(linearizationMethod, action);
- break;
- case POSTORDER:
- left.traverse(linearizationMethod, action);
- right.traverse(linearizationMethod, action);
- action.accept(token);
- break;
- case PREORDER:
- action.accept(token);
- left.traverse(linearizationMethod, action);
- right.traverse(linearizationMethod, action);
- break;
- default:
- throw new IllegalArgumentException(
- "Got a invalid tree linearizer "
- + linearizationMethod + ". WAT");
- }
- } else {
- action.accept(token);
- }
- }
-
- /**
* Collapse this tree into a single node
*
* @param <E>
@@ -104,11 +82,44 @@ public class AST<T> {
* The function for transforming the result
* @return The collapsed value of the tree
*/
+ @SuppressWarnings("unchecked")
public <E, T2> E collapse(Function<T, T2> tokenTransformer,
Function<T, BinaryOperator<T2>> nodeTransformer,
Function<T2, E> resultTransformer) {
- return resultTransformer.apply(
- internalCollapse(tokenTransformer, nodeTransformer));
+ if (tokenTransformer == null) {
+ throw new NullPointerException(
+ "Token transformer must not be null");
+ } else if (nodeTransformer == null) {
+ throw new NullPointerException(
+ "Node transformer must not be null");
+ }
+
+ if (resultTransformer != null) {
+ return resultTransformer.apply(
+ internalCollapse(tokenTransformer, nodeTransformer));
+ } else {
+ // This is valid because if the user passes null as the last
+ // parameter, E will be inferred as Object, but will actually
+ // be T2
+ return (E) internalCollapse(tokenTransformer, nodeTransformer);
+ }
+ }
+
+ /**
+ * Expand the nodes in an AST
+ *
+ * @param expander
+ * The function to use for expanding nodes
+ * @return The expanded AST
+ */
+ public AST<T> expand(Function<T, AST<T>> expander) {
+ if (expander == null) {
+ throw new NullPointerException("Expander must not be null");
+ }
+
+ return collapse(expander, (operator) -> (leftAST, rightAST) -> {
+ return new AST<>(operator, leftAST, rightAST);
+ }, null);
}
/*
@@ -129,6 +140,7 @@ public class AST<T> {
}
T2 rightCollapsed;
+
if (right == null) {
rightCollapsed = null;
} else {
@@ -141,15 +153,6 @@ public class AST<T> {
}
}
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
-
- internalToString(builder, -1);
-
- return builder.toString();
- }
-
/**
* Internal version of toString for proper rendering
*
@@ -187,21 +190,6 @@ public class AST<T> {
}
/**
- * Indent a string n levels
- *
- * @param builder
- * The string to indent
- * @param levels
- * The number of levels to indent
- */
- protected static void indentNLevels(StringBuilder builder,
- int levels) {
- for (int i = 0; i <= levels; i++) {
- builder.append("\t");
- }
- }
-
- /**
* Execute a transform on selective nodes of the tree
*
* @param transformerPredicate
@@ -211,6 +199,12 @@ public class AST<T> {
*/
public void selectiveTransform(Predicate<T> transformerPredicate,
UnaryOperator<T> transformer) {
+ if (transformerPredicate == null) {
+ throw new NullPointerException("Predicate must not be null");
+ } else if (transformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
if (transformerPredicate.test(token)) {
token = transformer.apply(token);
}
@@ -224,6 +218,15 @@ public class AST<T> {
}
}
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ internalToString(builder, -1);
+
+ return builder.toString();
+ }
+
/**
* Transmute the tokens in an AST into a different sort of token
*
@@ -235,6 +238,10 @@ public class AST<T> {
* @return The AST with transformed tokens
*/
public <E> AST<E> transmuteAST(Function<T, E> tokenTransformer) {
+ if (tokenTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
AST<E> leftBranch = null;
AST<E> rightBranch = null;
@@ -249,4 +256,48 @@ public class AST<T> {
return new AST<>(tokenTransformer.apply(token), leftBranch,
rightBranch);
}
+
+ /**
+ * Traverse an AST
+ *
+ * @param linearizationMethod
+ * The way to traverse the tree
+ * @param action
+ * The function to call on each traversed element
+ */
+ public void traverse(TreeLinearizationMethod linearizationMethod,
+ Consumer<T> action) {
+ if (linearizationMethod == null) {
+ throw new NullPointerException(
+ "Linearization method must not be null");
+ } else if (action == null) {
+ throw new NullPointerException("Action must not be null");
+ }
+
+ if (left != null && right != null) {
+ switch (linearizationMethod) {
+ case INORDER:
+ left.traverse(linearizationMethod, action);
+ action.accept(token);
+ right.traverse(linearizationMethod, action);
+ break;
+ case POSTORDER:
+ left.traverse(linearizationMethod, action);
+ right.traverse(linearizationMethod, action);
+ action.accept(token);
+ break;
+ case PREORDER:
+ action.accept(token);
+ left.traverse(linearizationMethod, action);
+ right.traverse(linearizationMethod, action);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Got a invalid tree linearizer "
+ + linearizationMethod + ". WAT");
+ }
+ } else {
+ action.accept(token);
+ }
+ }
}
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 46f5f1d..b6162e5 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java
@@ -2,6 +2,7 @@ package bjc.utils.parserutils;
import java.io.InputStream;
import java.util.HashMap;
+import java.util.InputMismatchException;
import java.util.Map;
import java.util.Scanner;
import java.util.function.BiConsumer;
@@ -58,6 +59,13 @@ public class RuleBasedConfigReader<E> {
*/
public void addPragma(String pragmaName,
BiConsumer<FunctionalStringTokenizer, E> pragmaAction) {
+ if (pragmaName == null) {
+ throw new NullPointerException("Pragma name must not be null");
+ } else if (pragmaAction == null) {
+ throw new NullPointerException(
+ "Pragma action must not be null");
+ }
+
pragmas.put(pragmaName, pragmaAction);
}
@@ -71,42 +79,77 @@ public class RuleBasedConfigReader<E> {
* @return The final state of the reader
*/
public E fromStream(InputStream inputStream, E initialState) {
- Scanner inputSource = new Scanner(inputStream);
-
- E state = initialState;
-
- while (inputSource.hasNextLine()) {
- String line = inputSource.nextLine();
-
- if (line.equals("")) {
- endRule.accept(state);
- continue;
- } else if (line.startsWith("\t")) {
- continueRule.accept(new FunctionalStringTokenizer(
- line.substring(1), " "), state);
- } else {
- FunctionalStringTokenizer tokenizer =
- new FunctionalStringTokenizer(line, " ");
-
- String nextToken = tokenizer.nextToken();
- if (nextToken.equals("#")) {
- // Do nothing, this is a comment
- } else if (nextToken.equals("pragma")) {
- String token = tokenizer.nextToken();
-
- pragmas.getOrDefault(token, (tokenzer, stat) -> {
- throw new UnknownPragmaException(
- "Unknown pragma " + token);
- }).accept(tokenizer, state);
+ if (inputStream == null) {
+ throw new NullPointerException(
+ "Input stream must not be null");
+ }
+
+ E state;
+
+ try (Scanner inputSource = new Scanner(inputStream)) {
+
+ state = initialState;
+ boolean ruleOpen = false;
+ while (inputSource.hasNextLine()) {
+ String line = inputSource.nextLine();
+
+ if (line.equals("")) {
+ if (ruleOpen == false) {
+ // Ignore blank line without an open rule
+ }
+
+ if (endRule == null) {
+ // Nothing happens on rule end
+ } else {
+ endRule.accept(state);
+ }
+
+ 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);
} else {
- startRule.accept(tokenizer,
- new Pair<>(nextToken, state));
+ FunctionalStringTokenizer tokenizer =
+ new FunctionalStringTokenizer(line, " ");
+
+ String nextToken = tokenizer.nextToken();
+
+ if (nextToken.equals("#") || nextToken.equals("//")) {
+ // Do nothing, this is a comment
+ } else 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;
+ }
}
}
}
- inputSource.close();
-
return state;
}
@@ -139,6 +182,11 @@ public class RuleBasedConfigReader<E> {
*/
public void setStartRule(
BiConsumer<FunctionalStringTokenizer, Pair<String, E>> startRule) {
+ if (startRule == null) {
+ throw new NullPointerException(
+ "Action on rule start must be non-null");
+ }
+
this.startRule = startRule;
}
}
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 0ca1879..1e5d487 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/ShuntingYard.java
@@ -19,42 +19,6 @@ import bjc.utils.funcutils.StringUtils;
* The type of tokens being shunted
*/
public class ShuntingYard<E> {
-
- private final class TokenShunter implements Consumer<String> {
- private FunctionalList<E> output;
- private Deque<String> stack;
- private Function<String, E> transform;
-
- public TokenShunter(FunctionalList<E> outpt, Deque<String> stack,
- Function<String, E> transform) {
- this.output = outpt;
- this.stack = stack;
- this.transform = transform;
- }
-
- @Override
- public void accept(String token) {
- if (operators.containsKey(token)) {
- while (!stack.isEmpty()
- && isHigherPrec(token, stack.peek())) {
- output.add(transform.apply(stack.pop()));
- }
-
- stack.push(token);
- } else if (StringUtils.containsOnly(token, "\\(")) {
- stack.push(token);
- } else if (StringUtils.containsOnly(token, "\\)")) {
- while (stack.peek().equals(token.replace(')', '('))) {
- output.add(transform.apply(stack.pop()));
- }
-
- stack.pop();
- } else {
- output.add(transform.apply(token));
- }
- }
- }
-
/**
* A enum representing the fundamental operator types
*
@@ -96,6 +60,58 @@ public class ShuntingYard<E> {
}
}
+ private final class TokenShunter implements Consumer<String> {
+ private FunctionalList<E> output;
+ private Deque<String> stack;
+ private Function<String, E> transform;
+
+ public TokenShunter(FunctionalList<E> outpt, Deque<String> stack,
+ Function<String, E> transform) {
+ this.output = outpt;
+ this.stack = stack;
+ this.transform = transform;
+ }
+
+ @Override
+ public void accept(String token) {
+ if (operators.containsKey(token)) {
+ while (!stack.isEmpty()
+ && isHigherPrec(token, stack.peek())) {
+ output.add(transform.apply(stack.pop()));
+ }
+
+ stack.push(token);
+ } else if (StringUtils.containsOnly(token, "\\(")) {
+ // Handle groups of parenthesis for multiple nesting levels
+ stack.push(token);
+ } else if (StringUtils.containsOnly(token, "\\)")) {
+ // Handle groups of parenthesis for multiple nesting levels
+ while (stack.peek().equals(token.replace(')', '('))) {
+ output.add(transform.apply(stack.pop()));
+ }
+
+ stack.pop();
+ } else {
+ output.add(transform.apply(token));
+ }
+ }
+ }
+
+ private static boolean shouldConfigureBasicOperators = true;
+
+ /**
+ * Set whether the shunter should configure the four basic math
+ * operators
+ *
+ * @param configureBasicOperators
+ * Whether or not the four basic math operators should be
+ * configured
+ */
+ public static void setBasicOperatorConfiguration(
+ boolean configureBasicOperators) {
+ shouldConfigureBasicOperators = configureBasicOperators;
+ }
+
/**
* Holds all the shuntable operations
*/
@@ -107,10 +123,12 @@ public class ShuntingYard<E> {
public ShuntingYard() {
operators = new HashMap<>();
- operators.put("+", Operator.ADD);
- operators.put("-", Operator.SUBTRACT);
- operators.put("*", Operator.MULTIPLY);
- operators.put("/", Operator.DIVIDE);
+ if (shouldConfigureBasicOperators) {
+ operators.put("+", Operator.ADD);
+ operators.put("-", Operator.SUBTRACT);
+ operators.put("*", Operator.MULTIPLY);
+ operators.put("/", Operator.DIVIDE);
+ }
}
/**
@@ -129,13 +147,17 @@ public class ShuntingYard<E> {
/**
* Add an operator to the list of shuntable operators
*
- * @param token
+ * @param operatorToken
* The token representing the operator
* @param precedence
* The precedence of the operator
*/
- public void addOp(String token, IPrecedent precedence) {
- operators.put(token, precedence);
+ public void addOp(String operatorToken, IPrecedent precedence) {
+ if (operatorToken == null) {
+ throw new NullPointerException("Operator must not be null");
+ }
+
+ operators.put(operatorToken, precedence);
}
private boolean isHigherPrec(String operator, String rightOperator) {
@@ -155,7 +177,14 @@ public class ShuntingYard<E> {
*/
public FunctionalList<E> postfix(FunctionalList<String> input,
Function<String, E> tokenTransformer) {
+ if (input == null) {
+ throw new NullPointerException("Input must not be null");
+ } else if (tokenTransformer == null) {
+ throw new NullPointerException("Transformer must not be null");
+ }
+
FunctionalList<E> output = new FunctionalList<>();
+
Deque<String> stack = new LinkedList<>();
input.forEach(new TokenShunter(output, stack, tokenTransformer));
@@ -174,6 +203,10 @@ public class ShuntingYard<E> {
* The token representing the operator
*/
public void removeOp(String tok) {
+ if (tok == null) {
+ throw new NullPointerException("Token must not be null");
+ }
+
operators.remove(tok);
}
} \ 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 42d5a9d..28ca1e3 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/TreeConstructor.java
@@ -2,10 +2,12 @@ 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 bjc.utils.data.GenHolder;
+import bjc.utils.data.IPair;
import bjc.utils.data.Pair;
import bjc.utils.funcdata.FunctionalList;
@@ -16,6 +18,89 @@ import bjc.utils.funcdata.FunctionalList;
*
*/
public class TreeConstructor {
+ private static final class TokenTransformer<T> implements Consumer<T> {
+ private final class OperatorHandler implements
+ Function<IPair<Deque<AST<T>>, AST<T>>, IPair<Deque<AST<T>>, AST<T>>> {
+ private T element;
+
+ public OperatorHandler(T element) {
+ this.element = element;
+ }
+
+ @Override
+ public IPair<Deque<AST<T>>, AST<T>>
+ apply(IPair<Deque<AST<T>>, AST<T>> pair) {
+ Deque<AST<T>> queuedASTs =
+ pair.merge((queue, currentAST) -> queue);
+
+ AST<T> mergedAST = pair.merge((queue, currentAST) -> {
+ AST<T> newAST;
+
+ if (isSpecialOperator.test(element)) {
+ newAST = handleSpecialOperator.apply(queue);
+ } else {
+ if (queue.size() < 2) {
+ throw new IllegalStateException(
+ "Attempted to parse binary operator without enough operands");
+ }
+
+ AST<T> rightAST = queue.pop();
+ AST<T> leftAST = queue.pop();
+
+ newAST = new AST<>(element, leftAST, rightAST);
+ }
+
+ queue.push(newAST);
+ return newAST;
+ });
+
+ Pair<Deque<AST<T>>, AST<T>> newPair =
+ new Pair<>(queuedASTs, mergedAST);
+
+ return newPair;
+ }
+ }
+
+ private GenHolder<IPair<Deque<AST<T>>, AST<T>>> initialState;
+ private Predicate<T> operatorPredicate;
+ private Predicate<T> isSpecialOperator;
+ private Function<Deque<AST<T>>, AST<T>> handleSpecialOperator;
+
+ public TokenTransformer(
+ GenHolder<IPair<Deque<AST<T>>, AST<T>>> initialState,
+ Predicate<T> operatorPredicate,
+ Predicate<T> isSpecialOperator,
+ Function<Deque<AST<T>>, AST<T>> 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 {
+ AST<T> newAST = new AST<>(element);
+
+ initialState.doWith((pair) -> {
+ pair.doWith((queue, currentAST) -> {
+ queue.push(newAST);
+ });
+ });
+
+ initialState.transform((pair) -> {
+ return pair.apply((Deque<AST<T>> queue) -> {
+ return queue;
+ }, (AST<T> currentAST) -> {
+ return newAST;
+ });
+ });
+ }
+ }
+ }
+
/**
* Construct a tree from a list of tokens in postfix notation
*
@@ -29,10 +114,6 @@ public class TreeConstructor {
* The predicate to use to determine if something is a
* operator
* @return A AST from the expression
- *
- * @deprecated Use
- * {@link TreeConstructor#constructTree(FunctionalList, Predicate, Predicate, Function)}
- * instead
*/
public static <T> AST<T> constructTree(FunctionalList<T> tokens,
Predicate<T> operatorPredicate) {
@@ -43,7 +124,8 @@ public class TreeConstructor {
/**
* Construct a tree from a list of tokens in postfix notation
*
- * Only binary operators are accepted.
+ * Only binary operators are accepted by default. Use the last two
+ * parameters to handle non-binary operators
*
* @param <T>
* The elements of the parse tree
@@ -66,52 +148,25 @@ public class TreeConstructor {
public static <T> AST<T> constructTree(FunctionalList<T> tokens,
Predicate<T> operatorPredicate, Predicate<T> isSpecialOperator,
Function<Deque<AST<T>>, AST<T>> handleSpecialOperator) {
- GenHolder<Pair<Deque<AST<T>>, AST<T>>> initialState =
- new GenHolder<>(new Pair<>(new LinkedList<>(), null));
-
- tokens.forEach((element) -> {
- if (operatorPredicate.test(element)) {
- initialState.transform((pair) -> {
- Deque<AST<T>> queuedASTs =
- pair.merge((queue, currentAST) -> queue);
-
- AST<T> mergedAST = pair.merge((queue, currentAST) -> {
- AST<T> newAST;
-
- if (isSpecialOperator.test(element)) {
- newAST = handleSpecialOperator.apply(queue);
- } else {
- AST<T> rightAST = queue.pop();
- AST<T> leftAST = queue.pop();
-
- newAST = new AST<>(element, leftAST, rightAST);
- }
+ if (tokens == null) {
+ throw new NullPointerException("Tokens must not be null");
+ } else if (operatorPredicate == null) {
+ throw new NullPointerException(
+ "Operator predicate must not be null");
+ } else if (isSpecialOperator == null) {
+ throw new NullPointerException(
+ "Special operator determiner must not be null");
+ }
- queue.push(newAST);
- return newAST;
- });
-
- Pair<Deque<AST<T>>, AST<T>> newPair =
- new Pair<>(queuedASTs, mergedAST);
-
- return newPair;
- });
- } else {
- AST<T> newAST = new AST<>(element);
+ GenHolder<IPair<Deque<AST<T>>, AST<T>>> initialState =
+ new GenHolder<>(new Pair<>(new LinkedList<>(), null));
- initialState.doWith(
- (pair) -> pair.doWith((queue, currentAST) -> {
- queue.push(newAST);
- }));
+ tokens.forEach(
+ new TokenTransformer<>(initialState, operatorPredicate,
+ isSpecialOperator, handleSpecialOperator));
- initialState.transform((pair) -> {
- return (Pair<Deque<AST<T>>, AST<T>>) pair.apply(
- (queue) -> queue, (currentAST) -> newAST);
- });
- }
+ return initialState.unwrap((pair) -> {
+ return pair.merge((queue, currentAST) -> currentAST);
});
-
- return initialState.unwrap(
- (pair) -> pair.merge((queue, currentAST) -> currentAST));
}
}