summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnits/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/sevenUnits/utils')
-rw-r--r--src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java2
-rw-r--r--src/main/java/sevenUnits/utils/ExpressionParser.java12
-rw-r--r--src/main/java/sevenUnits/utils/ObjectProduct.java135
-rw-r--r--src/main/java/sevenUnits/utils/UncertainDouble.java15
4 files changed, 88 insertions, 76 deletions
diff --git a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
index 2adb579..bee4dd1 100644
--- a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
+++ b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java
@@ -283,7 +283,7 @@ public final class ConditionalExistenceCollections {
@Override
public Set<K> keySet() {
- return conditionalExistenceSet(super.keySet(),
+ return conditionalExistenceSet(this.map.keySet(),
k -> this.entryExistenceCondition.test(this.getEntry(k)));
}
diff --git a/src/main/java/sevenUnits/utils/ExpressionParser.java b/src/main/java/sevenUnits/utils/ExpressionParser.java
index 1d3d44d..941c2a4 100644
--- a/src/main/java/sevenUnits/utils/ExpressionParser.java
+++ b/src/main/java/sevenUnits/utils/ExpressionParser.java
@@ -461,10 +461,12 @@ public final class ExpressionParser<T> {
*
* @param expression expression
* @return expression in RPN
+ * @throws IllegalArgumentException if expression is invalid (e.g.
+ * "{@code 3 *}")
* @since 2019-03-17
* @since v0.2.0
*/
- private String convertExpressionToReversePolish(final String expression) {
+ String convertExpressionToReversePolish(final String expression) {
Objects.requireNonNull(expression, "expression must not be null.");
final List<String> components = new ArrayList<>();
@@ -541,6 +543,9 @@ public final class ExpressionParser<T> {
switch (this
.getTokenType(components.get(highestPriorityOperatorPosition))) {
case UNARY_OPERATOR:
+ if (components.size() < 2)
+ throw new IllegalArgumentException(
+ "Invalid expression \"" + expression + "\"");
final String unaryOperator = components
.remove(highestPriorityOperatorPosition);
final String operand = components
@@ -549,6 +554,9 @@ public final class ExpressionParser<T> {
operand + " " + unaryOperator);
break;
case BINARY_OPERATOR:
+ if (components.size() < 3)
+ throw new IllegalArgumentException(
+ "Invalid expression \"" + expression + "\"");
final String binaryOperator = components
.remove(highestPriorityOperatorPosition);
final String operand1 = components
@@ -672,7 +680,7 @@ public final class ExpressionParser<T> {
* @since 2019-03-14
* @since v0.2.0
*/
- private T parseReversePolishExpression(final String expression) {
+ T parseReversePolishExpression(final String expression) {
Objects.requireNonNull(expression, "expression must not be null.");
final Deque<T> stack = new ArrayDeque<>();
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index 1dacb7d..5b1b739 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.java
@@ -27,8 +27,8 @@ import java.util.Set;
import java.util.function.Function;
/**
- * An immutable product of multiple objects of a type, such as base units. The objects can be multiplied and
- * exponentiated.
+ * An immutable product of multiple objects of a type, such as base units. The
+ * objects can be multiplied and exponentiated.
*
* @author Adrien Hopkins
* @since 2019-10-16
@@ -37,38 +37,35 @@ public final class ObjectProduct<T> {
/**
* Returns an empty ObjectProduct of a certain type
*
- * @param <T>
- * type of objects that can be multiplied
+ * @param <T> type of objects that can be multiplied
* @return empty product
* @since 2019-10-16
*/
public static final <T> ObjectProduct<T> empty() {
return new ObjectProduct<>(new HashMap<>());
}
-
+
/**
* Gets an {@code ObjectProduct} from an object-to-integer mapping
*
- * @param <T>
- * type of object in product
- * @param map
- * map mapping objects to exponents
+ * @param <T> type of object in product
+ * @param map map mapping objects to exponents
* @return object product
* @since 2019-10-16
*/
- public static final <T> ObjectProduct<T> fromExponentMapping(final Map<T, Integer> map) {
+ public static final <T> ObjectProduct<T> fromExponentMapping(
+ final Map<T, Integer> map) {
return new ObjectProduct<>(new HashMap<>(map));
}
-
+
/**
- * Gets an ObjectProduct that has one of the inputted argument, and nothing else.
+ * Gets an ObjectProduct that has one of the inputted argument, and nothing
+ * else.
*
- * @param object
- * object that will be in the product
+ * @param object object that will be in the product
* @return product
* @since 2019-10-16
- * @throws NullPointerException
- * if object is null
+ * @throws NullPointerException if object is null
*/
public static final <T> ObjectProduct<T> oneOf(final T object) {
Objects.requireNonNull(object, "object must not be null.");
@@ -76,35 +73,34 @@ public final class ObjectProduct<T> {
map.put(object, 1);
return new ObjectProduct<>(map);
}
-
+
/**
- * The objects that make up the product, mapped to their exponents. This map treats zero as null, and is immutable.
+ * The objects that make up the product, mapped to their exponents. This map
+ * treats zero as null, and is immutable.
*
* @since 2019-10-16
*/
final Map<T, Integer> exponents;
-
+
/**
* Creates the {@code ObjectProduct}.
*
- * @param exponents
- * objects that make up this product
+ * @param exponents objects that make up this product
* @since 2019-10-16
*/
private ObjectProduct(final Map<T, Integer> exponents) {
- this.exponents = Collections.unmodifiableMap(ConditionalExistenceCollections.conditionalExistenceMap(exponents,
- e -> !Integer.valueOf(0).equals(e.getValue())));
+ this.exponents = Collections.unmodifiableMap(
+ ConditionalExistenceCollections.conditionalExistenceMap(exponents,
+ e -> !Integer.valueOf(0).equals(e.getValue())));
}
-
+
/**
* Calculates the quotient of two products
*
- * @param other
- * other product
+ * @param other other product
* @return quotient of two products
* @since 2019-10-16
- * @throws NullPointerException
- * if other is null
+ * @throws NullPointerException if other is null
*/
public ObjectProduct<T> dividedBy(final ObjectProduct<T> other) {
Objects.requireNonNull(other, "other must not be null.");
@@ -112,17 +108,17 @@ public final class ObjectProduct<T> {
final Set<T> objects = new HashSet<>();
objects.addAll(this.getBaseSet());
objects.addAll(other.getBaseSet());
-
+
// get a list of all exponents
final Map<T, Integer> map = new HashMap<>(objects.size());
for (final T key : objects) {
map.put(key, this.getExponent(key) - other.getExponent(key));
}
-
+
// create the product
return new ObjectProduct<>(map);
}
-
+
// this method relies on the use of ZeroIsNullMap
@Override
public boolean equals(final Object obj) {
@@ -133,7 +129,7 @@ public final class ObjectProduct<T> {
final ObjectProduct<?> other = (ObjectProduct<?>) obj;
return Objects.equals(this.exponents, other.exponents);
}
-
+
/**
* @return immutable map mapping objects to exponents
* @since 2019-10-16
@@ -141,30 +137,31 @@ public final class ObjectProduct<T> {
public Map<T, Integer> exponentMap() {
return this.exponents;
}
-
+
/**
- * @return a set of all of the base objects with non-zero exponents that make up this dimension.
+ * @return a set of all of the base objects with non-zero exponents that make
+ * up this dimension.
* @since 2018-12-12
* @since v0.1.0
*/
public final Set<T> getBaseSet() {
final Set<T> dimensions = new HashSet<>();
-
- // add all dimensions with a nonzero exponent - zero exponents shouldn't be there in the first place
+
+ // add all dimensions with a nonzero exponent - zero exponents shouldn't
+ // be there in the first place
for (final T dimension : this.exponents.keySet()) {
if (!this.exponents.get(dimension).equals(0)) {
dimensions.add(dimension);
}
}
-
+
return dimensions;
}
-
+
/**
* Gets the exponent for a specific dimension.
*
- * @param dimension
- * dimension to check
+ * @param dimension dimension to check
* @return exponent for that dimension
* @since 2018-12-12
* @since v0.1.0
@@ -172,14 +169,15 @@ public final class ObjectProduct<T> {
public int getExponent(final T dimension) {
return this.exponents.getOrDefault(dimension, 0);
}
-
+
@Override
public int hashCode() {
return Objects.hash(this.exponents);
}
-
+
/**
- * @return true if this product is a single object, i.e. it has one exponent of one and no other nonzero exponents
+ * @return true if this product is a single object, i.e. it has one exponent
+ * of one and no other nonzero exponents
* @since 2019-10-16
*/
public boolean isSingleObject() {
@@ -194,16 +192,14 @@ public final class ObjectProduct<T> {
}
return oneCount == 1 && !twoOrMore;
}
-
+
/**
* Multiplies this product by another
*
- * @param other
- * other product
+ * @param other other product
* @return product of two products
* @since 2019-10-16
- * @throws NullPointerException
- * if other is null
+ * @throws NullPointerException if other is null
*/
public ObjectProduct<T> times(final ObjectProduct<T> other) {
Objects.requireNonNull(other, "other must not be null.");
@@ -211,22 +207,21 @@ public final class ObjectProduct<T> {
final Set<T> objects = new HashSet<>();
objects.addAll(this.getBaseSet());
objects.addAll(other.getBaseSet());
-
+
// get a list of all exponents
final Map<T, Integer> map = new HashMap<>(objects.size());
for (final T key : objects) {
map.put(key, this.getExponent(key) + other.getExponent(key));
}
-
+
// create the product
return new ObjectProduct<>(map);
}
-
+
/**
* Returns this product, but to an exponent
*
- * @param exponent
- * exponent
+ * @param exponent exponent
* @return result of exponentiation
* @since 2019-10-16
*/
@@ -237,11 +232,12 @@ public final class ObjectProduct<T> {
}
return new ObjectProduct<>(map);
}
-
+
/**
- * Converts this product to a string using the objects' {@link Object#toString()} method. If objects have a long
- * toString representation, it is recommended to use {@link #toString(Function)} instead to shorten the returned
- * string.
+ * Converts this product to a string using the objects'
+ * {@link Object#toString()} method. If objects have a long toString
+ * representation, it is recommended to use {@link #toString(Function)}
+ * instead to shorten the returned string.
*
* <p>
* {@inheritDoc}
@@ -250,35 +246,38 @@ public final class ObjectProduct<T> {
public String toString() {
return this.toString(Object::toString);
}
-
+
/**
- * Converts this product to a string. The objects that make up this product are represented by
- * {@code objectToString}
+ * Converts this product to a string. The objects that make up this product
+ * are represented by {@code objectToString}
*
- * @param objectToString
- * function to convert objects to strings
+ * @param objectToString function to convert objects to strings
* @return string representation of product
* @since 2019-10-16
*/
public String toString(final Function<T, String> objectToString) {
final List<String> positiveStringComponents = new ArrayList<>();
final List<String> negativeStringComponents = new ArrayList<>();
-
+
// for each base object that makes up this object, add it and its exponent
for (final T object : this.getBaseSet()) {
final int exponent = this.exponents.get(object);
- if (exponent > 0) {
- positiveStringComponents.add(String.format("%s^%d", objectToString.apply(object), exponent));
+ if (exponent > 1) {
+ positiveStringComponents.add(String.format("%s^%d",
+ objectToString.apply(object), exponent));
+ } else if (exponent == 1) {
+ positiveStringComponents.add(objectToString.apply(object));
} else if (exponent < 0) {
- negativeStringComponents.add(String.format("%s^%d", objectToString.apply(object), -exponent));
+ negativeStringComponents.add(String.format("%s^%d",
+ objectToString.apply(object), -exponent));
}
}
-
+
final String positiveString = positiveStringComponents.isEmpty() ? "1"
: String.join(" * ", positiveStringComponents);
final String negativeString = negativeStringComponents.isEmpty() ? ""
: " / " + String.join(" * ", negativeStringComponents);
-
+
return positiveString + negativeString;
}
}
diff --git a/src/main/java/sevenUnits/utils/UncertainDouble.java b/src/main/java/sevenUnits/utils/UncertainDouble.java
index 8fe4b31..fe41104 100644
--- a/src/main/java/sevenUnits/utils/UncertainDouble.java
+++ b/src/main/java/sevenUnits/utils/UncertainDouble.java
@@ -36,13 +36,14 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
*/
public static final UncertainDouble ZERO = UncertainDouble.of(0, 0);
+ static final String NUMBER_REGEX = "(\\d+(?:[\\.,]\\d+))";
+
/**
* A regular expression that can recognize toString forms
*/
- private static final Pattern TO_STRING = Pattern
- .compile("([a-zA-Z_0-9\\.\\,]+)" // a number
- // optional "± [number]"
- + "(?:\\s*(?:±|\\+-)\\s*([a-zA-Z_0-9\\.\\,]+))?");
+ static final Pattern TO_STRING = Pattern.compile(NUMBER_REGEX
+ // optional "± [number]"
+ + "(?:\\s*(?:±|\\+-)\\s*" + NUMBER_REGEX + ")?");
/**
* Parses a string in the form of {@link UncertainDouble#toString(boolean)}
@@ -60,10 +61,14 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
Objects.requireNonNull(s, "s may not be null");
final Matcher matcher = TO_STRING.matcher(s);
+ if (!matcher.matches())
+ throw new IllegalArgumentException(
+ "Could not parse stirng \"" + s + "\".");
+
double value, uncertainty;
try {
value = Double.parseDouble(matcher.group(1));
- } catch (IllegalStateException | NumberFormatException e) {
+ } catch (final NumberFormatException e) {
throw new IllegalArgumentException(
"String " + s + " not in correct format.");
}