summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/unitConverter/converterGUI/DefaultPrefixRepetitionRule.java (renamed from src/org/unitConverter/converterGUI/DefaultPrefixRepetitionRule.java)0
-rw-r--r--src/main/java/org/unitConverter/converterGUI/DelegateListModel.java (renamed from src/org/unitConverter/converterGUI/DelegateListModel.java)0
-rw-r--r--src/main/java/org/unitConverter/converterGUI/FilterComparator.java (renamed from src/org/unitConverter/converterGUI/FilterComparator.java)258
-rw-r--r--src/main/java/org/unitConverter/converterGUI/GridBagBuilder.java (renamed from src/org/unitConverter/converterGUI/GridBagBuilder.java)0
-rw-r--r--src/main/java/org/unitConverter/converterGUI/MutablePredicate.java (renamed from src/org/unitConverter/converterGUI/MutablePredicate.java)0
-rw-r--r--src/main/java/org/unitConverter/converterGUI/SearchBoxList.java (renamed from src/org/unitConverter/converterGUI/SearchBoxList.java)0
-rw-r--r--src/main/java/org/unitConverter/converterGUI/UnitConverterGUI.java (renamed from src/org/unitConverter/converterGUI/UnitConverterGUI.java)95
-rw-r--r--src/main/java/org/unitConverter/converterGUI/package-info.java (renamed from src/org/unitConverter/converterGUI/package-info.java)0
-rw-r--r--src/main/java/org/unitConverter/math/ConditionalExistenceCollections.java (renamed from src/org/unitConverter/math/ConditionalExistenceCollections.java)2
-rw-r--r--src/main/java/org/unitConverter/math/DecimalComparison.java (renamed from src/org/unitConverter/math/DecimalComparison.java)0
-rw-r--r--src/main/java/org/unitConverter/math/ExpressionParser.java (renamed from src/org/unitConverter/math/ExpressionParser.java)537
-rw-r--r--src/main/java/org/unitConverter/math/ObjectProduct.java (renamed from src/org/unitConverter/math/ObjectProduct.java)568
-rw-r--r--src/main/java/org/unitConverter/math/UncertainDouble.java (renamed from src/org/unitConverter/math/UncertainDouble.java)0
-rw-r--r--src/main/java/org/unitConverter/math/package-info.java (renamed from src/org/unitConverter/math/package-info.java)0
-rw-r--r--src/main/java/org/unitConverter/package-info.java (renamed from src/org/unitConverter/package-info.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/BaseDimension.java (renamed from src/org/unitConverter/unit/BaseDimension.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/BaseUnit.java (renamed from src/org/unitConverter/unit/BaseUnit.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/BritishImperial.java (renamed from src/org/unitConverter/unit/BritishImperial.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/FunctionalUnit.java (renamed from src/org/unitConverter/unit/FunctionalUnit.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/FunctionalUnitlike.java (renamed from src/org/unitConverter/unit/FunctionalUnitlike.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/LinearUnit.java (renamed from src/org/unitConverter/unit/LinearUnit.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/LinearUnitValue.java (renamed from src/org/unitConverter/unit/LinearUnitValue.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/MultiUnit.java (renamed from src/org/unitConverter/unit/MultiUnit.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/NameSymbol.java (renamed from src/org/unitConverter/unit/NameSymbol.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/Nameable.java (renamed from src/org/unitConverter/unit/Nameable.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/SI.java (renamed from src/org/unitConverter/unit/SI.java)958
-rw-r--r--src/main/java/org/unitConverter/unit/USCustomary.java (renamed from src/org/unitConverter/unit/USCustomary.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/Unit.java (renamed from src/org/unitConverter/unit/Unit.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/UnitDatabase.java (renamed from src/org/unitConverter/unit/UnitDatabase.java)34
-rw-r--r--src/main/java/org/unitConverter/unit/UnitPrefix.java (renamed from src/org/unitConverter/unit/UnitPrefix.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/UnitValue.java (renamed from src/org/unitConverter/unit/UnitValue.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/Unitlike.java (renamed from src/org/unitConverter/unit/Unitlike.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/UnitlikeValue.java (renamed from src/org/unitConverter/unit/UnitlikeValue.java)0
-rw-r--r--src/main/java/org/unitConverter/unit/package-info.java (renamed from src/org/unitConverter/unit/package-info.java)0
-rw-r--r--src/main/resources/about.txt (renamed from src/about.txt)0
-rw-r--r--src/main/resources/dimensionfile.txt18
-rw-r--r--src/main/resources/metric_exceptions.txt19
-rw-r--r--src/main/resources/unitsfile.txt267
-rw-r--r--src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java (renamed from src/org/unitConverter/math/ConditionalExistenceCollectionsTest.java)0
-rw-r--r--src/test/java/org/unitConverter/math/ExpressionParserTest.java (renamed from src/org/unitConverter/math/ExpressionParserTest.java)0
-rw-r--r--src/test/java/org/unitConverter/math/ObjectProductTest.java (renamed from src/org/unitConverter/math/ObjectProductTest.java)0
-rw-r--r--src/test/java/org/unitConverter/unit/MultiUnitTest.java (renamed from src/org/unitConverter/unit/MultiUnitTest.java)0
-rw-r--r--src/test/java/org/unitConverter/unit/UnitDatabaseTest.java (renamed from src/org/unitConverter/unit/UnitDatabaseTest.java)4
-rw-r--r--src/test/java/org/unitConverter/unit/UnitTest.java (renamed from src/org/unitConverter/unit/UnitTest.java)2
44 files changed, 1590 insertions, 1172 deletions
diff --git a/src/org/unitConverter/converterGUI/DefaultPrefixRepetitionRule.java b/src/main/java/org/unitConverter/converterGUI/DefaultPrefixRepetitionRule.java
index bdc3a2e..bdc3a2e 100644
--- a/src/org/unitConverter/converterGUI/DefaultPrefixRepetitionRule.java
+++ b/src/main/java/org/unitConverter/converterGUI/DefaultPrefixRepetitionRule.java
diff --git a/src/org/unitConverter/converterGUI/DelegateListModel.java b/src/main/java/org/unitConverter/converterGUI/DelegateListModel.java
index b80f63d..b80f63d 100644
--- a/src/org/unitConverter/converterGUI/DelegateListModel.java
+++ b/src/main/java/org/unitConverter/converterGUI/DelegateListModel.java
diff --git a/src/org/unitConverter/converterGUI/FilterComparator.java b/src/main/java/org/unitConverter/converterGUI/FilterComparator.java
index 7b17bfc..9b77f21 100644
--- a/src/org/unitConverter/converterGUI/FilterComparator.java
+++ b/src/main/java/org/unitConverter/converterGUI/FilterComparator.java
@@ -1,129 +1,129 @@
-/**
- * Copyright (C) 2018 Adrien Hopkins
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-package org.unitConverter.converterGUI;
-
-import java.util.Comparator;
-import java.util.Objects;
-
-/**
- * A comparator that compares strings using a filter.
- *
- * @author Adrien Hopkins
- * @since 2019-01-15
- * @since v0.1.0
- */
-final class FilterComparator implements Comparator<String> {
- /**
- * The filter that the comparator is filtered by.
- *
- * @since 2019-01-15
- * @since v0.1.0
- */
- private final String filter;
- /**
- * The comparator to use if the arguments are otherwise equal.
- *
- * @since 2019-01-15
- * @since v0.1.0
- */
- private final Comparator<String> comparator;
- /**
- * Whether or not the comparison is case-sensitive.
- *
- * @since 2019-04-14
- * @since v0.2.0
- */
- private final boolean caseSensitive;
-
- /**
- * Creates the {@code FilterComparator}.
- *
- * @param filter
- * @since 2019-01-15
- * @since v0.1.0
- */
- public FilterComparator(final String filter) {
- this(filter, null);
- }
-
- /**
- * Creates the {@code FilterComparator}.
- *
- * @param filter
- * string to filter by
- * @param comparator
- * comparator to fall back to if all else fails, null is compareTo.
- * @throws NullPointerException
- * if filter is null
- * @since 2019-01-15
- * @since v0.1.0
- */
- public FilterComparator(final String filter, final Comparator<String> comparator) {
- this(filter, comparator, false);
- }
-
- /**
- * Creates the {@code FilterComparator}.
- *
- * @param filter
- * string to filter by
- * @param comparator
- * comparator to fall back to if all else fails, null is compareTo.
- * @param caseSensitive
- * whether or not the comparator is case-sensitive
- * @throws NullPointerException
- * if filter is null
- * @since 2019-04-14
- * @since v0.2.0
- */
- public FilterComparator(final String filter, final Comparator<String> comparator, final boolean caseSensitive) {
- this.filter = Objects.requireNonNull(filter, "filter must not be null.");
- this.comparator = comparator;
- this.caseSensitive = caseSensitive;
- }
-
- @Override
- public int compare(final String arg0, final String arg1) {
- // if this is case insensitive, make them lowercase
- final String str0, str1;
- if (this.caseSensitive) {
- str0 = arg0;
- str1 = arg1;
- } else {
- str0 = arg0.toLowerCase();
- str1 = arg1.toLowerCase();
- }
-
- // elements that start with the filter always go first
- if (str0.startsWith(this.filter) && !str1.startsWith(this.filter))
- return -1;
- else if (!str0.startsWith(this.filter) && str1.startsWith(this.filter))
- return 1;
-
- // elements that contain the filter but don't start with them go next
- if (str0.contains(this.filter) && !str1.contains(this.filter))
- return -1;
- else if (!str0.contains(this.filter) && !str1.contains(this.filter))
- return 1;
-
- // other elements go last
- if (this.comparator == null)
- return str0.compareTo(str1);
- else
- return this.comparator.compare(str0, str1);
- }
-}
+/**
+ * Copyright (C) 2018 Adrien Hopkins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.unitConverter.converterGUI;
+
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A comparator that compares strings using a filter.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-01-15
+ * @since v0.1.0
+ */
+final class FilterComparator implements Comparator<String> {
+ /**
+ * The filter that the comparator is filtered by.
+ *
+ * @since 2019-01-15
+ * @since v0.1.0
+ */
+ private final String filter;
+ /**
+ * The comparator to use if the arguments are otherwise equal.
+ *
+ * @since 2019-01-15
+ * @since v0.1.0
+ */
+ private final Comparator<String> comparator;
+ /**
+ * Whether or not the comparison is case-sensitive.
+ *
+ * @since 2019-04-14
+ * @since v0.2.0
+ */
+ private final boolean caseSensitive;
+
+ /**
+ * Creates the {@code FilterComparator}.
+ *
+ * @param filter
+ * @since 2019-01-15
+ * @since v0.1.0
+ */
+ public FilterComparator(final String filter) {
+ this(filter, null);
+ }
+
+ /**
+ * Creates the {@code FilterComparator}.
+ *
+ * @param filter
+ * string to filter by
+ * @param comparator
+ * comparator to fall back to if all else fails, null is compareTo.
+ * @throws NullPointerException
+ * if filter is null
+ * @since 2019-01-15
+ * @since v0.1.0
+ */
+ public FilterComparator(final String filter, final Comparator<String> comparator) {
+ this(filter, comparator, false);
+ }
+
+ /**
+ * Creates the {@code FilterComparator}.
+ *
+ * @param filter
+ * string to filter by
+ * @param comparator
+ * comparator to fall back to if all else fails, null is compareTo.
+ * @param caseSensitive
+ * whether or not the comparator is case-sensitive
+ * @throws NullPointerException
+ * if filter is null
+ * @since 2019-04-14
+ * @since v0.2.0
+ */
+ public FilterComparator(final String filter, final Comparator<String> comparator, final boolean caseSensitive) {
+ this.filter = Objects.requireNonNull(filter, "filter must not be null.");
+ this.comparator = comparator;
+ this.caseSensitive = caseSensitive;
+ }
+
+ @Override
+ public int compare(final String arg0, final String arg1) {
+ // if this is case insensitive, make them lowercase
+ final String str0, str1;
+ if (this.caseSensitive) {
+ str0 = arg0;
+ str1 = arg1;
+ } else {
+ str0 = arg0.toLowerCase();
+ str1 = arg1.toLowerCase();
+ }
+
+ // elements that start with the filter always go first
+ if (str0.startsWith(this.filter) && !str1.startsWith(this.filter))
+ return -1;
+ else if (!str0.startsWith(this.filter) && str1.startsWith(this.filter))
+ return 1;
+
+ // elements that contain the filter but don't start with them go next
+ if (str0.contains(this.filter) && !str1.contains(this.filter))
+ return -1;
+ else if (!str0.contains(this.filter) && !str1.contains(this.filter))
+ return 1;
+
+ // other elements go last
+ if (this.comparator == null)
+ return str0.compareTo(str1);
+ else
+ return this.comparator.compare(str0, str1);
+ }
+}
diff --git a/src/org/unitConverter/converterGUI/GridBagBuilder.java b/src/main/java/org/unitConverter/converterGUI/GridBagBuilder.java
index f1229b2..f1229b2 100644
--- a/src/org/unitConverter/converterGUI/GridBagBuilder.java
+++ b/src/main/java/org/unitConverter/converterGUI/GridBagBuilder.java
diff --git a/src/org/unitConverter/converterGUI/MutablePredicate.java b/src/main/java/org/unitConverter/converterGUI/MutablePredicate.java
index e15b3cd..e15b3cd 100644
--- a/src/org/unitConverter/converterGUI/MutablePredicate.java
+++ b/src/main/java/org/unitConverter/converterGUI/MutablePredicate.java
diff --git a/src/org/unitConverter/converterGUI/SearchBoxList.java b/src/main/java/org/unitConverter/converterGUI/SearchBoxList.java
index 10ef589..10ef589 100644
--- a/src/org/unitConverter/converterGUI/SearchBoxList.java
+++ b/src/main/java/org/unitConverter/converterGUI/SearchBoxList.java
diff --git a/src/org/unitConverter/converterGUI/UnitConverterGUI.java b/src/main/java/org/unitConverter/converterGUI/UnitConverterGUI.java
index 6ddc4a0..ee1bcc3 100644
--- a/src/org/unitConverter/converterGUI/UnitConverterGUI.java
+++ b/src/main/java/org/unitConverter/converterGUI/UnitConverterGUI.java
@@ -23,6 +23,7 @@ import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.io.BufferedWriter;
import java.io.IOException;
+import java.io.InputStream;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
@@ -36,6 +37,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Scanner;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -93,13 +95,11 @@ final class UnitConverterGUI {
/** The default place where settings are stored. */
private static final String DEFAULT_SETTINGS_FILEPATH = "settings.txt";
/** The default place where units are stored. */
- private static final Path DEFAULT_UNITS_FILE = Path.of("unitsfile.txt");
+ private static final String DEFAULT_UNITS_FILEPATH = "/unitsfile.txt";
/** The default place where dimensions are stored. */
- private static final Path DEFAULT_DIMENSION_FILE = Path
- .of("dimensionfile.txt");
+ private static final String DEFAULT_DIMENSIONS_FILEPATH = "/dimensionfile.txt";
/** The default place where exceptions are stored. */
- private static final Path DEFAULT_EXCEPTIONS_FILE = Path
- .of("metric_exceptions.txt");
+ private static final String DEFAULT_EXCEPTIONS_FILEPATH = "/metric_exceptions.txt";
/**
* Adds default units and dimensions to a database.
@@ -131,6 +131,41 @@ final class UnitConverterGUI {
}
/**
+ * Gets the text of a resource file as a set of strings (each one is one
+ * line of the text).
+ *
+ * @param filename filename to get resource from
+ * @return contents of file
+ * @since 2021-03-27
+ */
+ public static final List<String> getLinesFromResource(String filename) {
+ final List<String> lines = new ArrayList<>();
+
+ try (InputStream stream = inputStream(filename);
+ Scanner scanner = new Scanner(stream)) {
+ while (scanner.hasNextLine()) {
+ lines.add(scanner.nextLine());
+ }
+ } catch (final IOException e) {
+ throw new AssertionError(
+ "Error occurred while loading file " + filename, e);
+ }
+
+ return lines;
+ }
+
+ /**
+ * Gets an input stream for a resource file.
+ *
+ * @param filepath file to use as resource
+ * @return obtained Path
+ * @since 2021-03-27
+ */
+ private static final InputStream inputStream(String filepath) {
+ return UnitConverterGUI.class.getResourceAsStream(filepath);
+ }
+
+ /**
* @return {@code line} with any comments removed.
* @since 2021-03-13
*/
@@ -161,9 +196,9 @@ final class UnitConverterGUI {
/** A boolean remembering whether or not one-way conversion is on */
private boolean oneWay = true;
-
/** The prefix rule */
private DefaultPrefixRepetitionRule prefixRule = null;
+
// conditions for existence of From and To entries
// used for one-way conversion
private final MutablePredicate<String> fromExistenceCondition = new MutablePredicate<>(
@@ -196,21 +231,44 @@ final class UnitConverterGUI {
DefaultPrefixRepetitionRule.NO_RESTRICTION);
Presenter.addDefaults(this.database);
- this.database.loadUnitsFile(DEFAULT_UNITS_FILE);
- this.database.loadDimensionFile(DEFAULT_DIMENSION_FILE);
+ // load units and prefixes
+ try (final InputStream units = inputStream(DEFAULT_UNITS_FILEPATH)) {
+ this.database.loadUnitsFromStream(units);
+ } catch (final IOException e) {
+ throw new AssertionError("Loading of unitsfile.txt failed.", e);
+ }
+
+ // load dimensions
+ try (final InputStream dimensions = inputStream(
+ DEFAULT_DIMENSIONS_FILEPATH)) {
+ this.database.loadDimensionsFromStream(dimensions);
+ } catch (final IOException e) {
+ throw new AssertionError("Loading of dimensionfile.txt failed.", e);
+ }
// load metric exceptions
try {
- this.metricExceptions = Files.readAllLines(DEFAULT_EXCEPTIONS_FILE)
- .stream().map(Presenter::withoutComments)
- .filter(s -> !s.isBlank()).collect(Collectors.toSet());
+ this.metricExceptions = new HashSet<>();
+ try (InputStream exceptions = inputStream(
+ DEFAULT_EXCEPTIONS_FILEPATH);
+ Scanner scanner = new Scanner(exceptions)) {
+ while (scanner.hasNextLine()) {
+ final String line = Presenter
+ .withoutComments(scanner.nextLine());
+ if (!line.isBlank()) {
+ this.metricExceptions.add(line);
+ }
+ }
+ }
} catch (final IOException e) {
throw new AssertionError("Loading of metric_exceptions.txt failed.",
e);
}
// load settings - requires database to exist
- this.loadSettings();
+ if (Files.exists(this.getSettingsFile())) {
+ this.loadSettings();
+ }
// a comparator that can be used to compare prefix names
// any name that does not exist is less than a name that does.
@@ -1139,15 +1197,10 @@ final class UnitConverterGUI {
infoPanel.add(infoTextArea);
// get info text
- final String infoText;
- try {
- final Path aboutFile = Path.of("src", "about.txt");
- infoText = Files.readAllLines(aboutFile).stream()
- .map(Presenter::withoutComments)
- .collect(Collectors.joining("\n"));
- } catch (final IOException e) {
- throw new AssertionError("I/O exception loading about.txt");
- }
+ final String infoText = Presenter
+ .getLinesFromResource("/about.txt").stream()
+ .map(Presenter::withoutComments)
+ .collect(Collectors.joining("\n"));
infoTextArea.setText(infoText);
}
diff --git a/src/org/unitConverter/converterGUI/package-info.java b/src/main/java/org/unitConverter/converterGUI/package-info.java
index d85ecab..d85ecab 100644
--- a/src/org/unitConverter/converterGUI/package-info.java
+++ b/src/main/java/org/unitConverter/converterGUI/package-info.java
diff --git a/src/org/unitConverter/math/ConditionalExistenceCollections.java b/src/main/java/org/unitConverter/math/ConditionalExistenceCollections.java
index ac1c0cf..000658b 100644
--- a/src/org/unitConverter/math/ConditionalExistenceCollections.java
+++ b/src/main/java/org/unitConverter/math/ConditionalExistenceCollections.java
@@ -263,7 +263,7 @@ public final class ConditionalExistenceCollections {
}
private final Entry<K, V> getEntry(K key) {
- return new Entry<K, V>() {
+ return new Entry<>() {
@Override
public K getKey() {
return key;
diff --git a/src/org/unitConverter/math/DecimalComparison.java b/src/main/java/org/unitConverter/math/DecimalComparison.java
index 0f5b91e..0f5b91e 100644
--- a/src/org/unitConverter/math/DecimalComparison.java
+++ b/src/main/java/org/unitConverter/math/DecimalComparison.java
diff --git a/src/org/unitConverter/math/ExpressionParser.java b/src/main/java/org/unitConverter/math/ExpressionParser.java
index 8a0e97d..deee51d 100644
--- a/src/org/unitConverter/math/ExpressionParser.java
+++ b/src/main/java/org/unitConverter/math/ExpressionParser.java
@@ -32,8 +32,7 @@ import java.util.function.UnaryOperator;
* An object that can parse expressions with unary or binary operators.
*
* @author Adrien Hopkins
- * @param <T>
- * type of object that exists in parsed expressions
+ * @param <T> type of object that exists in parsed expressions
* @since 2019-03-14
* @since v0.2.0
*/
@@ -42,21 +41,21 @@ public final class ExpressionParser<T> {
* A builder that can create {@code ExpressionParser<T>} instances.
*
* @author Adrien Hopkins
- * @param <T>
- * type of object that exists in parsed expressions
+ * @param <T> type of object that exists in parsed expressions
* @since 2019-03-17
* @since v0.2.0
*/
public static final class Builder<T> {
/**
- * A function that obtains a parseable object from a string. For example, an integer {@code ExpressionParser}
- * would use {@code Integer::parseInt}.
+ * A function that obtains a parseable object from a string. For example,
+ * an integer {@code ExpressionParser} would use
+ * {@code Integer::parseInt}.
*
* @since 2019-03-14
* @since v0.2.0
*/
private final Function<String, ? extends T> objectObtainer;
-
+
/**
* The function of the space as an operator (like 3 x y)
*
@@ -64,110 +63,115 @@ public final class ExpressionParser<T> {
* @since v0.2.0
*/
private String spaceFunction = null;
-
+
/**
- * A map mapping operator strings to operator functions, for unary operators.
+ * A map mapping operator strings to operator functions, for unary
+ * operators.
*
* @since 2019-03-14
* @since v0.2.0
*/
private final Map<String, PriorityUnaryOperator<T>> unaryOperators;
-
+
/**
- * A map mapping operator strings to operator functions, for binary operators.
+ * A map mapping operator strings to operator functions, for binary
+ * operators.
*
* @since 2019-03-14
* @since v0.2.0
*/
private final Map<String, PriorityBinaryOperator<T>> binaryOperators;
-
+
/**
* Creates the {@code Builder}.
*
- * @param objectObtainer
- * a function that can turn strings into objects of the type handled by the parser.
- * @throws NullPointerException
- * if {@code objectObtainer} is null
+ * @param objectObtainer a function that can turn strings into objects of
+ * the type handled by the parser.
+ * @throws NullPointerException if {@code objectObtainer} is null
* @since 2019-03-17
* @since v0.2.0
*/
public Builder(final Function<String, ? extends T> objectObtainer) {
- this.objectObtainer = Objects.requireNonNull(objectObtainer, "objectObtainer must not be null.");
+ this.objectObtainer = Objects.requireNonNull(objectObtainer,
+ "objectObtainer must not be null.");
this.unaryOperators = new HashMap<>();
this.binaryOperators = new HashMap<>();
}
-
+
/**
* Adds a binary operator to the builder.
*
- * @param text
- * text used to reference the operator, like '+'
- * @param operator
- * operator to add
- * @param priority
- * operator's priority, which determines which operators are applied first
+ * @param text text used to reference the operator, like '+'
+ * @param operator operator to add
+ * @param priority operator's priority, which determines which operators
+ * are applied first
* @return this builder
- * @throws NullPointerException
- * if {@code text} or {@code operator} is null
+ * @throws NullPointerException if {@code text} or {@code operator} is
+ * null
* @since 2019-03-17
* @since v0.2.0
*/
- public Builder<T> addBinaryOperator(final String text, final BinaryOperator<T> operator, final int priority) {
+ public Builder<T> addBinaryOperator(final String text,
+ final BinaryOperator<T> operator, final int priority) {
Objects.requireNonNull(text, "text must not be null.");
Objects.requireNonNull(operator, "operator must not be null.");
-
- // Unfortunately, I cannot use a lambda because the PriorityBinaryOperator requires arguments.
- final PriorityBinaryOperator<T> priorityOperator = new PriorityBinaryOperator<T>(priority) {
+
+ // Unfortunately, I cannot use a lambda because the
+ // PriorityBinaryOperator requires arguments.
+ final PriorityBinaryOperator<T> priorityOperator = new PriorityBinaryOperator<>(
+ priority) {
@Override
public T apply(final T t, final T u) {
return operator.apply(t, u);
}
-
+
};
this.binaryOperators.put(text, priorityOperator);
return this;
}
-
+
/**
- * Adds a function for spaces. You must use the text of an existing binary operator.
+ * Adds a function for spaces. You must use the text of an existing binary
+ * operator.
*
- * @param operator
- * text of operator to use
+ * @param operator text of operator to use
* @return this builder
* @since 2019-03-22
* @since v0.2.0
*/
public Builder<T> addSpaceFunction(final String operator) {
Objects.requireNonNull(operator, "operator must not be null.");
-
+
if (!this.binaryOperators.containsKey(operator))
- throw new IllegalArgumentException(String.format("Could not find binary operator '%s'", operator));
-
+ throw new IllegalArgumentException(String
+ .format("Could not find binary operator '%s'", operator));
+
this.spaceFunction = operator;
return this;
}
-
+
/**
* Adds a unary operator to the builder.
*
- * @param text
- * text used to reference the operator, like '-'
- * @param operator
- * operator to add
- * @param priority
- * operator's priority, which determines which operators are applied first
+ * @param text text used to reference the operator, like '-'
+ * @param operator operator to add
+ * @param priority operator's priority, which determines which operators
+ * are applied first
* @return this builder
- * @throws NullPointerException
- * if {@code text} or {@code operator} is null
+ * @throws NullPointerException if {@code text} or {@code operator} is
+ * null
* @since 2019-03-17
* @since v0.2.0
*/
- public Builder<T> addUnaryOperator(final String text, final UnaryOperator<T> operator, final int priority) {
+ public Builder<T> addUnaryOperator(final String text,
+ final UnaryOperator<T> operator, final int priority) {
Objects.requireNonNull(text, "text must not be null.");
Objects.requireNonNull(operator, "operator must not be null.");
-
- // Unfortunately, I cannot use a lambda because the PriorityUnaryOperator requires arguments.
- final PriorityUnaryOperator<T> priorityOperator = new PriorityUnaryOperator<T>(priority) {
+
+ // Unfortunately, I cannot use a lambda because the
+ // PriorityUnaryOperator requires arguments.
+ final PriorityUnaryOperator<T> priorityOperator = new PriorityUnaryOperator<>(
+ priority) {
@Override
public T apply(final T t) {
return operator.apply(t);
@@ -176,49 +180,50 @@ public final class ExpressionParser<T> {
this.unaryOperators.put(text, priorityOperator);
return this;
}
-
+
/**
- * @return an {@code ExpressionParser<T>} instance with the properties given to this builder
+ * @return an {@code ExpressionParser<T>} instance with the properties
+ * given to this builder
* @since 2019-03-17
* @since v0.2.0
*/
public ExpressionParser<T> build() {
- return new ExpressionParser<>(this.objectObtainer, this.unaryOperators, this.binaryOperators,
- this.spaceFunction);
+ return new ExpressionParser<>(this.objectObtainer, this.unaryOperators,
+ this.binaryOperators, this.spaceFunction);
}
}
-
+
/**
- * A binary operator with a priority field that determines which operators apply first.
+ * A binary operator with a priority field that determines which operators
+ * apply first.
*
* @author Adrien Hopkins
- * @param <T>
- * type of operand and result
+ * @param <T> type of operand and result
* @since 2019-03-17
* @since v0.2.0
*/
private static abstract class PriorityBinaryOperator<T>
implements BinaryOperator<T>, Comparable<PriorityBinaryOperator<T>> {
/**
- * The operator's priority. Higher-priority operators are applied before lower-priority operators
+ * The operator's priority. Higher-priority operators are applied before
+ * lower-priority operators
*
* @since 2019-03-17
* @since v0.2.0
*/
private final int priority;
-
+
/**
* Creates the {@code PriorityBinaryOperator}.
*
- * @param priority
- * operator's priority
+ * @param priority operator's priority
* @since 2019-03-17
* @since v0.2.0
*/
public PriorityBinaryOperator(final int priority) {
this.priority = priority;
}
-
+
/**
* Compares this object to another by priority.
*
@@ -238,7 +243,7 @@ public final class ExpressionParser<T> {
else
return 0;
}
-
+
/**
* @return priority
* @since 2019-03-22
@@ -248,38 +253,38 @@ public final class ExpressionParser<T> {
return this.priority;
}
}
-
+
/**
- * A unary operator with a priority field that determines which operators apply first.
+ * A unary operator with a priority field that determines which operators
+ * apply first.
*
* @author Adrien Hopkins
- * @param <T>
- * type of operand and result
+ * @param <T> type of operand and result
* @since 2019-03-17
* @since v0.2.0
*/
private static abstract class PriorityUnaryOperator<T>
implements UnaryOperator<T>, Comparable<PriorityUnaryOperator<T>> {
/**
- * The operator's priority. Higher-priority operators are applied before lower-priority operators
+ * The operator's priority. Higher-priority operators are applied before
+ * lower-priority operators
*
* @since 2019-03-17
* @since v0.2.0
*/
private final int priority;
-
+
/**
* Creates the {@code PriorityUnaryOperator}.
*
- * @param priority
- * operator's priority
+ * @param priority operator's priority
* @since 2019-03-17
* @since v0.2.0
*/
public PriorityUnaryOperator(final int priority) {
this.priority = priority;
}
-
+
/**
* Compares this object to another by priority.
*
@@ -299,7 +304,7 @@ public final class ExpressionParser<T> {
else
return 0;
}
-
+
/**
* @return priority
* @since 2019-03-22
@@ -309,7 +314,7 @@ public final class ExpressionParser<T> {
return this.priority;
}
}
-
+
/**
* The types of tokens that are available.
*
@@ -320,7 +325,7 @@ public final class ExpressionParser<T> {
private static enum TokenType {
OBJECT, UNARY_OPERATOR, BINARY_OPERATOR;
}
-
+
/**
* The opening bracket.
*
@@ -328,7 +333,7 @@ public final class ExpressionParser<T> {
* @since v0.2.0
*/
public static final char OPENING_BRACKET = '(';
-
+
/**
* The closing bracket.
*
@@ -336,48 +341,49 @@ public final class ExpressionParser<T> {
* @since v0.2.0
*/
public static final char CLOSING_BRACKET = ')';
-
+
/**
* Finds the other bracket in a pair of brackets, given the position of one.
*
- * @param string
- * string that contains brackets
- * @param bracketPosition
- * position of first bracket
+ * @param string string that contains brackets
+ * @param bracketPosition position of first bracket
* @return position of matching bracket
- * @throws NullPointerException
- * if string is null
+ * @throws NullPointerException if string is null
* @since 2019-03-22
* @since v0.2.0
*/
- private static int findBracketPair(final String string, final int bracketPosition) {
+ private static int findBracketPair(final String string,
+ final int bracketPosition) {
Objects.requireNonNull(string, "string must not be null.");
-
+
final char openingBracket = string.charAt(bracketPosition);
-
+
// figure out what closing bracket to look for
final char closingBracket;
switch (openingBracket) {
- case '(':
- closingBracket = ')';
- break;
- case '[':
- closingBracket = ']';
- break;
- case '{':
- closingBracket = '}';
- break;
- default:
- throw new IllegalArgumentException(String.format("Invalid bracket '%s'", openingBracket));
+ case '(':
+ closingBracket = ')';
+ break;
+ case '[':
+ closingBracket = ']';
+ break;
+ case '{':
+ closingBracket = '}';
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Invalid bracket '%s'", openingBracket));
}
-
- // level of brackets. every opening bracket increments this; every closing bracket decrements it
+
+ // level of brackets. every opening bracket increments this; every closing
+ // bracket decrements it
int bracketLevel = 0;
-
+
// iterate over the string to find the closing bracket
- for (int currentPosition = bracketPosition; currentPosition < string.length(); currentPosition++) {
+ for (int currentPosition = bracketPosition; currentPosition < string
+ .length(); currentPosition++) {
final char currentCharacter = string.charAt(currentPosition);
-
+
if (currentCharacter == openingBracket) {
bracketLevel++;
} else if (currentCharacter == closingBracket) {
@@ -386,19 +392,19 @@ public final class ExpressionParser<T> {
return currentPosition;
}
}
-
+
throw new IllegalArgumentException("No matching bracket found.");
}
-
+
/**
- * A function that obtains a parseable object from a string. For example, an integer {@code ExpressionParser} would
- * use {@code Integer::parseInt}.
+ * A function that obtains a parseable object from a string. For example, an
+ * integer {@code ExpressionParser} would use {@code Integer::parseInt}.
*
* @since 2019-03-14
* @since v0.2.0
*/
private final Function<String, ? extends T> objectObtainer;
-
+
/**
* A map mapping operator strings to operator functions, for unary operators.
*
@@ -406,15 +412,16 @@ public final class ExpressionParser<T> {
* @since v0.2.0
*/
private final Map<String, PriorityUnaryOperator<T>> unaryOperators;
-
+
/**
- * A map mapping operator strings to operator functions, for binary operators.
+ * A map mapping operator strings to operator functions, for binary
+ * operators.
*
* @since 2019-03-14
* @since v0.2.0
*/
private final Map<String, PriorityBinaryOperator<T>> binaryOperators;
-
+
/**
* The operator for space, or null if spaces have no function.
*
@@ -422,127 +429,144 @@ public final class ExpressionParser<T> {
* @since v0.2.0
*/
private final String spaceOperator;
-
+
/**
* Creates the {@code ExpressionParser}.
*
- * @param objectObtainer
- * function to get objects from strings
- * @param unaryOperators
- * unary operators available to the parser
- * @param binaryOperators
- * binary operators available to the parser
- * @param spaceOperator
- * operator used by spaces
+ * @param objectObtainer function to get objects from strings
+ * @param unaryOperators unary operators available to the parser
+ * @param binaryOperators binary operators available to the parser
+ * @param spaceOperator operator used by spaces
* @since 2019-03-14
* @since v0.2.0
*/
private ExpressionParser(final Function<String, ? extends T> objectObtainer,
final Map<String, PriorityUnaryOperator<T>> unaryOperators,
- final Map<String, PriorityBinaryOperator<T>> binaryOperators, final String spaceOperator) {
+ final Map<String, PriorityBinaryOperator<T>> binaryOperators,
+ final String spaceOperator) {
this.objectObtainer = objectObtainer;
this.unaryOperators = unaryOperators;
this.binaryOperators = binaryOperators;
this.spaceOperator = spaceOperator;
}
-
+
/**
- * Converts a given mathematical expression to reverse Polish notation (operators after operands).
+ * Converts a given mathematical expression to reverse Polish notation
+ * (operators after operands).
* <p>
* For example,<br>
* {@code 2 * (3 + 4)}<br>
* becomes<br>
* {@code 2 3 4 + *}.
*
- * @param expression
- * expression
+ * @param expression expression
* @return expression in RPN
* @since 2019-03-17
* @since v0.2.0
*/
private String convertExpressionToReversePolish(final String expression) {
Objects.requireNonNull(expression, "expression must not be null.");
-
+
final List<String> components = new ArrayList<>();
-
+
// the part of the expression remaining to parse
String partialExpression = expression;
-
+
// find and deal with brackets
while (partialExpression.indexOf(OPENING_BRACKET) != -1) {
- final int openingBracketPosition = partialExpression.indexOf(OPENING_BRACKET);
- final int closingBracketPosition = findBracketPair(partialExpression, openingBracketPosition);
-
+ final int openingBracketPosition = partialExpression
+ .indexOf(OPENING_BRACKET);
+ final int closingBracketPosition = findBracketPair(partialExpression,
+ openingBracketPosition);
+
// check for function
- if (openingBracketPosition > 0 && partialExpression.charAt(openingBracketPosition - 1) != ' ') {
+ if (openingBracketPosition > 0
+ && partialExpression.charAt(openingBracketPosition - 1) != ' ') {
// function like sin(2) or tempF(32)
// find the position of the last space
int spacePosition = openingBracketPosition;
- while (spacePosition >= 0 && partialExpression.charAt(spacePosition) != ' ') {
+ while (spacePosition >= 0
+ && partialExpression.charAt(spacePosition) != ' ') {
spacePosition--;
}
- // then split the function into pre-function and function, using the space position
- components.addAll(Arrays.asList(partialExpression.substring(0, spacePosition + 1).split(" ")));
- components.add(partialExpression.substring(spacePosition + 1, closingBracketPosition + 1));
- partialExpression = partialExpression.substring(closingBracketPosition + 1);
+ // then split the function into pre-function and function, using the
+ // space position
+ components.addAll(Arrays.asList(partialExpression
+ .substring(0, spacePosition + 1).split(" ")));
+ components.add(partialExpression.substring(spacePosition + 1,
+ closingBracketPosition + 1));
+ partialExpression = partialExpression
+ .substring(closingBracketPosition + 1);
} else {
// normal brackets like (1 + 2) * (3 / 5)
- components.addAll(Arrays.asList(partialExpression.substring(0, openingBracketPosition).split(" ")));
+ components.addAll(Arrays.asList(partialExpression
+ .substring(0, openingBracketPosition).split(" ")));
components.add(this.convertExpressionToReversePolish(
- partialExpression.substring(openingBracketPosition + 1, closingBracketPosition)));
- partialExpression = partialExpression.substring(closingBracketPosition + 1);
+ partialExpression.substring(openingBracketPosition + 1,
+ closingBracketPosition)));
+ partialExpression = partialExpression
+ .substring(closingBracketPosition + 1);
}
}
-
+
// add everything else
components.addAll(Arrays.asList(partialExpression.split(" ")));
-
+
// remove empty entries
while (components.contains("")) {
components.remove("");
}
-
+
// deal with space multiplication (x y)
if (this.spaceOperator != null) {
for (int i = 0; i < components.size() - 1; i++) {
- if (this.getTokenType(components.get(i)) == TokenType.OBJECT
- && this.getTokenType(components.get(i + 1)) == TokenType.OBJECT) {
+ if (this.getTokenType(components.get(i)) == TokenType.OBJECT && this
+ .getTokenType(components.get(i + 1)) == TokenType.OBJECT) {
components.add(++i, this.spaceOperator);
}
}
}
-
+
// turn the expression into reverse Polish
while (true) {
- final int highestPriorityOperatorPosition = this.findHighestPriorityOperatorPosition(components);
+ final int highestPriorityOperatorPosition = this
+ .findHighestPriorityOperatorPosition(components);
if (highestPriorityOperatorPosition == -1) {
break;
}
-
+
// swap components based on what kind of operator there is
// 1 + 2 becomes 2 1 +
// - 1 becomes 1 -
- switch (this.getTokenType(components.get(highestPriorityOperatorPosition))) {
- case UNARY_OPERATOR:
- final String unaryOperator = components.remove(highestPriorityOperatorPosition);
- final String operand = components.remove(highestPriorityOperatorPosition);
- components.add(highestPriorityOperatorPosition, operand + " " + unaryOperator);
- break;
- case BINARY_OPERATOR:
- final String binaryOperator = components.remove(highestPriorityOperatorPosition);
- final String operand1 = components.remove(highestPriorityOperatorPosition - 1);
- final String operand2 = components.remove(highestPriorityOperatorPosition - 1);
- components.add(highestPriorityOperatorPosition - 1,
- operand2 + " " + operand1 + " " + binaryOperator);
- break;
- default:
- throw new AssertionError("Expected operator, found non-operator.");
+ switch (this
+ .getTokenType(components.get(highestPriorityOperatorPosition))) {
+ case UNARY_OPERATOR:
+ final String unaryOperator = components
+ .remove(highestPriorityOperatorPosition);
+ final String operand = components
+ .remove(highestPriorityOperatorPosition);
+ components.add(highestPriorityOperatorPosition,
+ operand + " " + unaryOperator);
+ break;
+ case BINARY_OPERATOR:
+ final String binaryOperator = components
+ .remove(highestPriorityOperatorPosition);
+ final String operand1 = components
+ .remove(highestPriorityOperatorPosition - 1);
+ final String operand2 = components
+ .remove(highestPriorityOperatorPosition - 1);
+ components.add(highestPriorityOperatorPosition - 1,
+ operand2 + " " + operand1 + " " + binaryOperator);
+ break;
+ default:
+ throw new AssertionError("Expected operator, found non-operator.");
}
}
-
- // join all of the components together, then ensure there is only one space in a row
+
+ // join all of the components together, then ensure there is only one
+ // space in a row
String expressionRPN = String.join(" ", components).replaceAll(" +", " ");
-
+
while (expressionRPN.charAt(0) == ' ') {
expressionRPN = expressionRPN.substring(1);
}
@@ -551,73 +575,72 @@ public final class ExpressionParser<T> {
}
return expressionRPN;
}
-
+
/**
* Finds the position of the highest-priority operator in a list
*
- * @param components
- * components to test
- * @param blacklist
- * positions of operators that should be ignored
- * @return position of highest priority, or -1 if the list contains no operators
- * @throws NullPointerException
- * if components is null
+ * @param components components to test
+ * @param blacklist positions of operators that should be ignored
+ * @return position of highest priority, or -1 if the list contains no
+ * operators
+ * @throws NullPointerException if components is null
* @since 2019-03-22
* @since v0.2.0
*/
- private int findHighestPriorityOperatorPosition(final List<String> components) {
+ private int findHighestPriorityOperatorPosition(
+ final List<String> components) {
Objects.requireNonNull(components, "components must not be null.");
// find highest priority
int maxPriority = Integer.MIN_VALUE;
int maxPriorityPosition = -1;
-
+
// go over components one by one
// if it is an operator, test its priority to see if it's max
// if it is, update maxPriority and maxPriorityPosition
for (int i = 0; i < components.size(); i++) {
-
+
switch (this.getTokenType(components.get(i))) {
- case UNARY_OPERATOR:
- final PriorityUnaryOperator<T> unaryOperator = this.unaryOperators.get(components.get(i));
- final int unaryPriority = unaryOperator.getPriority();
-
- if (unaryPriority > maxPriority) {
- maxPriority = unaryPriority;
- maxPriorityPosition = i;
- }
- break;
- case BINARY_OPERATOR:
- final PriorityBinaryOperator<T> binaryOperator = this.binaryOperators.get(components.get(i));
- final int binaryPriority = binaryOperator.getPriority();
-
- if (binaryPriority > maxPriority) {
- maxPriority = binaryPriority;
- maxPriorityPosition = i;
- }
- break;
- default:
- break;
+ case UNARY_OPERATOR:
+ final PriorityUnaryOperator<T> unaryOperator = this.unaryOperators
+ .get(components.get(i));
+ final int unaryPriority = unaryOperator.getPriority();
+
+ if (unaryPriority > maxPriority) {
+ maxPriority = unaryPriority;
+ maxPriorityPosition = i;
+ }
+ break;
+ case BINARY_OPERATOR:
+ final PriorityBinaryOperator<T> binaryOperator = this.binaryOperators
+ .get(components.get(i));
+ final int binaryPriority = binaryOperator.getPriority();
+
+ if (binaryPriority > maxPriority) {
+ maxPriority = binaryPriority;
+ maxPriorityPosition = i;
+ }
+ break;
+ default:
+ break;
}
}
-
+
// max priority position found
return maxPriorityPosition;
}
-
+
/**
* Determines whether an inputted string is an object or an operator
*
- * @param token
- * string to input
+ * @param token string to input
* @return type of token it is
- * @throws NullPointerException
- * if {@code expression} is null
+ * @throws NullPointerException if {@code expression} is null
* @since 2019-03-14
* @since v0.2.0
*/
private TokenType getTokenType(final String token) {
Objects.requireNonNull(token, "token must not be null.");
-
+
if (this.unaryOperators.containsKey(token))
return TokenType.UNARY_OPERATOR;
else if (this.binaryOperators.containsKey(token))
@@ -625,84 +648,88 @@ public final class ExpressionParser<T> {
else
return TokenType.OBJECT;
}
-
+
/**
* Parses an expression.
*
- * @param expression
- * expression to parse
+ * @param expression expression to parse
* @return result
- * @throws NullPointerException
- * if {@code expression} is null
+ * @throws NullPointerException if {@code expression} is null
* @since 2019-03-14
* @since v0.2.0
*/
public T parseExpression(final String expression) {
- return this.parseReversePolishExpression(this.convertExpressionToReversePolish(expression));
+ return this.parseReversePolishExpression(
+ this.convertExpressionToReversePolish(expression));
}
-
+
/**
* Parses an expression expressed in reverse Polish notation.
*
- * @param expression
- * expression to parse
+ * @param expression expression to parse
* @return result
- * @throws NullPointerException
- * if {@code expression} is null
+ * @throws NullPointerException if {@code expression} is null
* @since 2019-03-14
* @since v0.2.0
*/
private T parseReversePolishExpression(final String expression) {
Objects.requireNonNull(expression, "expression must not be null.");
-
+
final Deque<T> stack = new ArrayDeque<>();
-
+
// iterate over every item in the expression, then
for (final String item : expression.split(" ")) {
// choose a path based on what kind of thing was just read
switch (this.getTokenType(item)) {
-
- case BINARY_OPERATOR:
- if (stack.size() < 2)
- throw new IllegalStateException(String.format(
- "Attempted to call binary operator %s with only %d arguments.", item, stack.size()));
-
- // get two arguments and operator, then apply!
- final T o1 = stack.pop();
- final T o2 = stack.pop();
- final BinaryOperator<T> binaryOperator = this.binaryOperators.get(item);
-
- stack.push(binaryOperator.apply(o1, o2));
- break;
-
- case OBJECT:
- // just add it to the stack
- stack.push(this.objectObtainer.apply(item));
- break;
-
- case UNARY_OPERATOR:
- if (stack.size() < 1)
- throw new IllegalStateException(String.format(
- "Attempted to call unary operator %s with only %d arguments.", item, stack.size()));
-
- // get one argument and operator, then apply!
- final T o = stack.pop();
- final UnaryOperator<T> unaryOperator = this.unaryOperators.get(item);
-
- stack.push(unaryOperator.apply(o));
- break;
- default:
- throw new AssertionError(
- String.format("Internal error: Invalid token type %s.", this.getTokenType(item)));
-
+
+ case BINARY_OPERATOR:
+ if (stack.size() < 2)
+ throw new IllegalStateException(String.format(
+ "Attempted to call binary operator %s with only %d arguments.",
+ item, stack.size()));
+
+ // get two arguments and operator, then apply!
+ final T o1 = stack.pop();
+ final T o2 = stack.pop();
+ final BinaryOperator<T> binaryOperator = this.binaryOperators
+ .get(item);
+
+ stack.push(binaryOperator.apply(o1, o2));
+ break;
+
+ case OBJECT:
+ // just add it to the stack
+ stack.push(this.objectObtainer.apply(item));
+ break;
+
+ case UNARY_OPERATOR:
+ if (stack.size() < 1)
+ throw new IllegalStateException(String.format(
+ "Attempted to call unary operator %s with only %d arguments.",
+ item, stack.size()));
+
+ // get one argument and operator, then apply!
+ final T o = stack.pop();
+ final UnaryOperator<T> unaryOperator = this.unaryOperators
+ .get(item);
+
+ stack.push(unaryOperator.apply(o));
+ break;
+ default:
+ throw new AssertionError(
+ String.format("Internal error: Invalid token type %s.",
+ this.getTokenType(item)));
+
}
}
-
+
// return answer, or throw an exception if I can't
if (stack.size() > 1)
- throw new IllegalStateException("Computation ended up with more than one answer.");
+ throw new IllegalStateException(
+ "Computation ended up with more than one answer.");
else if (stack.size() == 0)
- throw new IllegalStateException("Computation ended up without an answer.");
+ throw new IllegalStateException(
+ "Computation ended up without an answer.");
return stack.pop();
}
}
diff --git a/src/org/unitConverter/math/ObjectProduct.java b/src/main/java/org/unitConverter/math/ObjectProduct.java
index bf00647..5217d93 100644
--- a/src/org/unitConverter/math/ObjectProduct.java
+++ b/src/main/java/org/unitConverter/math/ObjectProduct.java
@@ -1,284 +1,284 @@
-/**
- * Copyright (C) 2018 Adrien Hopkins
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-package org.unitConverter.math;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-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.
- *
- * @author Adrien Hopkins
- * @since 2019-10-16
- */
-public final class ObjectProduct<T> {
- /**
- * Returns an empty ObjectProduct of a certain type
- *
- * @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
- * @return object product
- * @since 2019-10-16
- */
- 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.
- *
- * @param object
- * object that will be in the product
- * @return product
- * @since 2019-10-16
- * @throws NullPointerException
- * if object is null
- */
- public static final <T> ObjectProduct<T> oneOf(final T object) {
- Objects.requireNonNull(object, "object must not be null.");
- final Map<T, Integer> map = new HashMap<>();
- 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.
- *
- * @since 2019-10-16
- */
- final Map<T, Integer> exponents;
-
- /**
- * Creates the {@code ObjectProduct}.
- *
- * @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())));
- }
-
- /**
- * Calculates the quotient of two products
- *
- * @param other
- * other product
- * @return quotient of two products
- * @since 2019-10-16
- * @throws NullPointerException
- * if other is null
- */
- public ObjectProduct<T> dividedBy(final ObjectProduct<T> other) {
- Objects.requireNonNull(other, "other must not be null.");
- // get a list of all objects in both sets
- 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) {
- if (this == obj)
- return true;
- if (!(obj instanceof ObjectProduct))
- return false;
- final ObjectProduct<?> other = (ObjectProduct<?>) obj;
- return Objects.equals(this.exponents, other.exponents);
- }
-
- /**
- * @return immutable map mapping objects to exponents
- * @since 2019-10-16
- */
- 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.
- * @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
- 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
- * @return exponent for that dimension
- * @since 2018-12-12
- * @since v0.1.0
- */
- 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
- * @since 2019-10-16
- */
- public boolean isSingleObject() {
- int oneCount = 0;
- boolean twoOrMore = false; // has exponents of 2 or more
- for (final T b : this.getBaseSet()) {
- if (this.getExponent(b) == 1) {
- oneCount++;
- } else if (this.getExponent(b) != 0) {
- twoOrMore = true;
- }
- }
- return oneCount == 1 && !twoOrMore;
- }
-
- /**
- * Multiplies this product by another
- *
- * @param other
- * other product
- * @return product of two products
- * @since 2019-10-16
- * @throws NullPointerException
- * if other is null
- */
- public ObjectProduct<T> times(final ObjectProduct<T> other) {
- Objects.requireNonNull(other, "other must not be null.");
- // get a list of all objects in both sets
- 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
- * @return result of exponentiation
- * @since 2019-10-16
- */
- public ObjectProduct<T> toExponent(final int exponent) {
- final Map<T, Integer> map = new HashMap<>(this.exponents);
- for (final T key : this.exponents.keySet()) {
- map.put(key, this.getExponent(key) * exponent);
- }
- 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.
- *
- * <p>
- * {@inheritDoc}
- */
- @Override
- 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}
- *
- * @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));
- } else if (exponent < 0) {
- 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;
- }
-}
+/**
+ * Copyright (C) 2018 Adrien Hopkins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.unitConverter.math;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+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.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-10-16
+ */
+public final class ObjectProduct<T> {
+ /**
+ * Returns an empty ObjectProduct of a certain type
+ *
+ * @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
+ * @return object product
+ * @since 2019-10-16
+ */
+ 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.
+ *
+ * @param object
+ * object that will be in the product
+ * @return product
+ * @since 2019-10-16
+ * @throws NullPointerException
+ * if object is null
+ */
+ public static final <T> ObjectProduct<T> oneOf(final T object) {
+ Objects.requireNonNull(object, "object must not be null.");
+ final Map<T, Integer> map = new HashMap<>();
+ 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.
+ *
+ * @since 2019-10-16
+ */
+ final Map<T, Integer> exponents;
+
+ /**
+ * Creates the {@code ObjectProduct}.
+ *
+ * @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())));
+ }
+
+ /**
+ * Calculates the quotient of two products
+ *
+ * @param other
+ * other product
+ * @return quotient of two products
+ * @since 2019-10-16
+ * @throws NullPointerException
+ * if other is null
+ */
+ public ObjectProduct<T> dividedBy(final ObjectProduct<T> other) {
+ Objects.requireNonNull(other, "other must not be null.");
+ // get a list of all objects in both sets
+ 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) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof ObjectProduct))
+ return false;
+ final ObjectProduct<?> other = (ObjectProduct<?>) obj;
+ return Objects.equals(this.exponents, other.exponents);
+ }
+
+ /**
+ * @return immutable map mapping objects to exponents
+ * @since 2019-10-16
+ */
+ 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.
+ * @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
+ 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
+ * @return exponent for that dimension
+ * @since 2018-12-12
+ * @since v0.1.0
+ */
+ 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
+ * @since 2019-10-16
+ */
+ public boolean isSingleObject() {
+ int oneCount = 0;
+ boolean twoOrMore = false; // has exponents of 2 or more
+ for (final T b : this.getBaseSet()) {
+ if (this.getExponent(b) == 1) {
+ oneCount++;
+ } else if (this.getExponent(b) != 0) {
+ twoOrMore = true;
+ }
+ }
+ return oneCount == 1 && !twoOrMore;
+ }
+
+ /**
+ * Multiplies this product by another
+ *
+ * @param other
+ * other product
+ * @return product of two products
+ * @since 2019-10-16
+ * @throws NullPointerException
+ * if other is null
+ */
+ public ObjectProduct<T> times(final ObjectProduct<T> other) {
+ Objects.requireNonNull(other, "other must not be null.");
+ // get a list of all objects in both sets
+ 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
+ * @return result of exponentiation
+ * @since 2019-10-16
+ */
+ public ObjectProduct<T> toExponent(final int exponent) {
+ final Map<T, Integer> map = new HashMap<>(this.exponents);
+ for (final T key : this.exponents.keySet()) {
+ map.put(key, this.getExponent(key) * exponent);
+ }
+ 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.
+ *
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ 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}
+ *
+ * @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));
+ } else if (exponent < 0) {
+ 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/org/unitConverter/math/UncertainDouble.java b/src/main/java/org/unitConverter/math/UncertainDouble.java
index 3651bd5..3651bd5 100644
--- a/src/org/unitConverter/math/UncertainDouble.java
+++ b/src/main/java/org/unitConverter/math/UncertainDouble.java
diff --git a/src/org/unitConverter/math/package-info.java b/src/main/java/org/unitConverter/math/package-info.java
index 65727e4..65727e4 100644
--- a/src/org/unitConverter/math/package-info.java
+++ b/src/main/java/org/unitConverter/math/package-info.java
diff --git a/src/org/unitConverter/package-info.java b/src/main/java/org/unitConverter/package-info.java
index 23dd165..23dd165 100644
--- a/src/org/unitConverter/package-info.java
+++ b/src/main/java/org/unitConverter/package-info.java
diff --git a/src/org/unitConverter/unit/BaseDimension.java b/src/main/java/org/unitConverter/unit/BaseDimension.java
index 8e63a17..8e63a17 100644
--- a/src/org/unitConverter/unit/BaseDimension.java
+++ b/src/main/java/org/unitConverter/unit/BaseDimension.java
diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/main/java/org/unitConverter/unit/BaseUnit.java
index 6757bd0..6757bd0 100644
--- a/src/org/unitConverter/unit/BaseUnit.java
+++ b/src/main/java/org/unitConverter/unit/BaseUnit.java
diff --git a/src/org/unitConverter/unit/BritishImperial.java b/src/main/java/org/unitConverter/unit/BritishImperial.java
index ea23cd1..ea23cd1 100644
--- a/src/org/unitConverter/unit/BritishImperial.java
+++ b/src/main/java/org/unitConverter/unit/BritishImperial.java
diff --git a/src/org/unitConverter/unit/FunctionalUnit.java b/src/main/java/org/unitConverter/unit/FunctionalUnit.java
index 586e0d7..586e0d7 100644
--- a/src/org/unitConverter/unit/FunctionalUnit.java
+++ b/src/main/java/org/unitConverter/unit/FunctionalUnit.java
diff --git a/src/org/unitConverter/unit/FunctionalUnitlike.java b/src/main/java/org/unitConverter/unit/FunctionalUnitlike.java
index 21c1fca..21c1fca 100644
--- a/src/org/unitConverter/unit/FunctionalUnitlike.java
+++ b/src/main/java/org/unitConverter/unit/FunctionalUnitlike.java
diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/main/java/org/unitConverter/unit/LinearUnit.java
index b7f33d5..b7f33d5 100644
--- a/src/org/unitConverter/unit/LinearUnit.java
+++ b/src/main/java/org/unitConverter/unit/LinearUnit.java
diff --git a/src/org/unitConverter/unit/LinearUnitValue.java b/src/main/java/org/unitConverter/unit/LinearUnitValue.java
index 8de734e..8de734e 100644
--- a/src/org/unitConverter/unit/LinearUnitValue.java
+++ b/src/main/java/org/unitConverter/unit/LinearUnitValue.java
diff --git a/src/org/unitConverter/unit/MultiUnit.java b/src/main/java/org/unitConverter/unit/MultiUnit.java
index a1623f8..a1623f8 100644
--- a/src/org/unitConverter/unit/MultiUnit.java
+++ b/src/main/java/org/unitConverter/unit/MultiUnit.java
diff --git a/src/org/unitConverter/unit/NameSymbol.java b/src/main/java/org/unitConverter/unit/NameSymbol.java
index 8d8302a..8d8302a 100644
--- a/src/org/unitConverter/unit/NameSymbol.java
+++ b/src/main/java/org/unitConverter/unit/NameSymbol.java
diff --git a/src/org/unitConverter/unit/Nameable.java b/src/main/java/org/unitConverter/unit/Nameable.java
index 36740ab..36740ab 100644
--- a/src/org/unitConverter/unit/Nameable.java
+++ b/src/main/java/org/unitConverter/unit/Nameable.java
diff --git a/src/org/unitConverter/unit/SI.java b/src/main/java/org/unitConverter/unit/SI.java
index c88d2bc..81736f3 100644
--- a/src/org/unitConverter/unit/SI.java
+++ b/src/main/java/org/unitConverter/unit/SI.java
@@ -1,479 +1,479 @@
-/**
- * Copyright (C) 2018 Adrien Hopkins
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-package org.unitConverter.unit;
-
-import java.util.Set;
-
-import org.unitConverter.math.ObjectProduct;
-
-/**
- * All of the units, prefixes and dimensions that are used by the SI, as well as
- * some outside the SI.
- *
- * <p>
- * This class does not include prefixed units. To obtain prefixed units, use
- * {@link LinearUnit#withPrefix}:
- *
- * <pre>
- * LinearUnit KILOMETRE = SI.METRE.withPrefix(SI.KILO);
- * </pre>
- *
- *
- * @author Adrien Hopkins
- * @since 2019-10-16
- */
-public final class SI {
- /// dimensions used by SI units
- // base dimensions, as BaseDimensions
- public static final class BaseDimensions {
- public static final BaseDimension LENGTH = BaseDimension.valueOf("Length",
- "L");
- public static final BaseDimension MASS = BaseDimension.valueOf("Mass",
- "M");
- public static final BaseDimension TIME = BaseDimension.valueOf("Time",
- "T");
- public static final BaseDimension ELECTRIC_CURRENT = BaseDimension
- .valueOf("Electric Current", "I");
- public static final BaseDimension TEMPERATURE = BaseDimension
- .valueOf("Temperature", "\u0398"); // theta symbol
- public static final BaseDimension QUANTITY = BaseDimension
- .valueOf("Quantity", "N");
- public static final BaseDimension LUMINOUS_INTENSITY = BaseDimension
- .valueOf("Luminous Intensity", "J");
- public static final BaseDimension INFORMATION = BaseDimension
- .valueOf("Information", "Info"); // non-SI
- public static final BaseDimension CURRENCY = BaseDimension
- .valueOf("Currency", "$$"); // non-SI
-
- // You may NOT get SI.BaseDimensions instances!
- private BaseDimensions() {
- throw new AssertionError();
- }
- }
-
- /// base units of the SI
- // suppressing warnings since these are the same object, but in a different
- /// form (class)
- @SuppressWarnings("hiding")
- public static final class BaseUnits {
- public static final BaseUnit METRE = BaseUnit
- .valueOf(BaseDimensions.LENGTH, "metre", "m");
- public static final BaseUnit KILOGRAM = BaseUnit
- .valueOf(BaseDimensions.MASS, "kilogram", "kg");
- public static final BaseUnit SECOND = BaseUnit
- .valueOf(BaseDimensions.TIME, "second", "s");
- public static final BaseUnit AMPERE = BaseUnit
- .valueOf(BaseDimensions.ELECTRIC_CURRENT, "ampere", "A");
- public static final BaseUnit KELVIN = BaseUnit
- .valueOf(BaseDimensions.TEMPERATURE, "kelvin", "K");
- public static final BaseUnit MOLE = BaseUnit
- .valueOf(BaseDimensions.QUANTITY, "mole", "mol");
- public static final BaseUnit CANDELA = BaseUnit
- .valueOf(BaseDimensions.LUMINOUS_INTENSITY, "candela", "cd");
- public static final BaseUnit BIT = BaseUnit
- .valueOf(BaseDimensions.INFORMATION, "bit", "b");
- public static final BaseUnit DOLLAR = BaseUnit
- .valueOf(BaseDimensions.CURRENCY, "dollar", "$");
-
- public static final Set<BaseUnit> BASE_UNITS = Set.of(METRE, KILOGRAM,
- SECOND, AMPERE, KELVIN, MOLE, CANDELA, BIT);
-
- // You may NOT get SI.BaseUnits instances!
- private BaseUnits() {
- throw new AssertionError();
- }
- }
-
- /**
- * Constants that relate to the SI or other systems.
- *
- * @author Adrien Hopkins
- * @since 2019-11-08
- */
- public static final class Constants {
- public static final LinearUnit EARTH_GRAVITY = METRE.dividedBy(SECOND)
- .dividedBy(SECOND).times(9.80665);
- }
-
- // dimensions used in the SI, as ObjectProducts
- public static final class Dimensions {
- public static final ObjectProduct<BaseDimension> EMPTY = ObjectProduct
- .empty();
- public static final ObjectProduct<BaseDimension> LENGTH = ObjectProduct
- .oneOf(BaseDimensions.LENGTH);
- public static final ObjectProduct<BaseDimension> MASS = ObjectProduct
- .oneOf(BaseDimensions.MASS);
- public static final ObjectProduct<BaseDimension> TIME = ObjectProduct
- .oneOf(BaseDimensions.TIME);
- public static final ObjectProduct<BaseDimension> ELECTRIC_CURRENT = ObjectProduct
- .oneOf(BaseDimensions.ELECTRIC_CURRENT);
- public static final ObjectProduct<BaseDimension> TEMPERATURE = ObjectProduct
- .oneOf(BaseDimensions.TEMPERATURE);
- public static final ObjectProduct<BaseDimension> QUANTITY = ObjectProduct
- .oneOf(BaseDimensions.QUANTITY);
- public static final ObjectProduct<BaseDimension> LUMINOUS_INTENSITY = ObjectProduct
- .oneOf(BaseDimensions.LUMINOUS_INTENSITY);
- public static final ObjectProduct<BaseDimension> INFORMATION = ObjectProduct
- .oneOf(BaseDimensions.INFORMATION);
- public static final ObjectProduct<BaseDimension> CURRENCY = ObjectProduct
- .oneOf(BaseDimensions.CURRENCY);
-
- // derived dimensions without named SI units
- public static final ObjectProduct<BaseDimension> AREA = LENGTH
- .times(LENGTH);
- public static final ObjectProduct<BaseDimension> VOLUME = AREA
- .times(LENGTH);
- public static final ObjectProduct<BaseDimension> VELOCITY = LENGTH
- .dividedBy(TIME);
- public static final ObjectProduct<BaseDimension> ACCELERATION = VELOCITY
- .dividedBy(TIME);
- public static final ObjectProduct<BaseDimension> WAVENUMBER = EMPTY
- .dividedBy(LENGTH);
- public static final ObjectProduct<BaseDimension> MASS_DENSITY = MASS
- .dividedBy(VOLUME);
- public static final ObjectProduct<BaseDimension> SURFACE_DENSITY = MASS
- .dividedBy(AREA);
- public static final ObjectProduct<BaseDimension> SPECIFIC_VOLUME = VOLUME
- .dividedBy(MASS);
- public static final ObjectProduct<BaseDimension> CURRENT_DENSITY = ELECTRIC_CURRENT
- .dividedBy(AREA);
- public static final ObjectProduct<BaseDimension> MAGNETIC_FIELD_STRENGTH = ELECTRIC_CURRENT
- .dividedBy(LENGTH);
- public static final ObjectProduct<BaseDimension> CONCENTRATION = QUANTITY
- .dividedBy(VOLUME);
- public static final ObjectProduct<BaseDimension> MASS_CONCENTRATION = CONCENTRATION
- .times(MASS);
- public static final ObjectProduct<BaseDimension> LUMINANCE = LUMINOUS_INTENSITY
- .dividedBy(AREA);
- public static final ObjectProduct<BaseDimension> REFRACTIVE_INDEX = VELOCITY
- .dividedBy(VELOCITY);
- public static final ObjectProduct<BaseDimension> REFRACTIVE_PERMEABILITY = EMPTY
- .times(EMPTY);
- public static final ObjectProduct<BaseDimension> ANGLE = LENGTH
- .dividedBy(LENGTH);
- public static final ObjectProduct<BaseDimension> SOLID_ANGLE = AREA
- .dividedBy(AREA);
-
- // derived dimensions with named SI units
- public static final ObjectProduct<BaseDimension> FREQUENCY = EMPTY
- .dividedBy(TIME);
- public static final ObjectProduct<BaseDimension> FORCE = MASS
- .times(ACCELERATION);
- public static final ObjectProduct<BaseDimension> ENERGY = FORCE
- .times(LENGTH);
- public static final ObjectProduct<BaseDimension> POWER = ENERGY
- .dividedBy(TIME);
- public static final ObjectProduct<BaseDimension> ELECTRIC_CHARGE = ELECTRIC_CURRENT
- .times(TIME);
- public static final ObjectProduct<BaseDimension> VOLTAGE = ENERGY
- .dividedBy(ELECTRIC_CHARGE);
- public static final ObjectProduct<BaseDimension> CAPACITANCE = ELECTRIC_CHARGE
- .dividedBy(VOLTAGE);
- public static final ObjectProduct<BaseDimension> ELECTRIC_RESISTANCE = VOLTAGE
- .dividedBy(ELECTRIC_CURRENT);
- public static final ObjectProduct<BaseDimension> ELECTRIC_CONDUCTANCE = ELECTRIC_CURRENT
- .dividedBy(VOLTAGE);
- public static final ObjectProduct<BaseDimension> MAGNETIC_FLUX = VOLTAGE
- .times(TIME);
- public static final ObjectProduct<BaseDimension> MAGNETIC_FLUX_DENSITY = MAGNETIC_FLUX
- .dividedBy(AREA);
- public static final ObjectProduct<BaseDimension> INDUCTANCE = MAGNETIC_FLUX
- .dividedBy(ELECTRIC_CURRENT);
- public static final ObjectProduct<BaseDimension> LUMINOUS_FLUX = LUMINOUS_INTENSITY
- .times(SOLID_ANGLE);
- public static final ObjectProduct<BaseDimension> ILLUMINANCE = LUMINOUS_FLUX
- .dividedBy(AREA);
- public static final ObjectProduct<BaseDimension> SPECIFIC_ENERGY = ENERGY
- .dividedBy(MASS);
- public static final ObjectProduct<BaseDimension> CATALYTIC_ACTIVITY = QUANTITY
- .dividedBy(TIME);
-
- // You may NOT get SI.Dimension instances!
- private Dimensions() {
- throw new AssertionError();
- }
- }
-
- /// The units of the SI
- public static final LinearUnit ONE = LinearUnit
- .valueOf(ObjectProduct.empty(), 1);
-
- public static final LinearUnit METRE = BaseUnits.METRE.asLinearUnit()
- .withName(NameSymbol.of("metre", "m", "meter"));
- public static final LinearUnit KILOGRAM = BaseUnits.KILOGRAM.asLinearUnit()
- .withName(NameSymbol.of("kilogram", "kg"));
- public static final LinearUnit SECOND = BaseUnits.SECOND.asLinearUnit()
- .withName(NameSymbol.of("second", "s", "sec"));
- public static final LinearUnit AMPERE = BaseUnits.AMPERE.asLinearUnit()
- .withName(NameSymbol.of("ampere", "A"));
- public static final LinearUnit KELVIN = BaseUnits.KELVIN.asLinearUnit()
- .withName(NameSymbol.of("kelvin", "K"));
- public static final LinearUnit MOLE = BaseUnits.MOLE.asLinearUnit()
- .withName(NameSymbol.of("mole", "mol"));
- public static final LinearUnit CANDELA = BaseUnits.CANDELA.asLinearUnit()
- .withName(NameSymbol.of("candela", "cd"));
- public static final LinearUnit BIT = BaseUnits.BIT.asLinearUnit()
- .withName(NameSymbol.of("bit", "b"));
- public static final LinearUnit DOLLAR = BaseUnits.DOLLAR.asLinearUnit()
- .withName(NameSymbol.of("dollar", "$"));
- // Non-base units
- public static final LinearUnit RADIAN = METRE.dividedBy(METRE)
- .withName(NameSymbol.of("radian", "rad"));
-
- public static final LinearUnit STERADIAN = RADIAN.times(RADIAN)
- .withName(NameSymbol.of("steradian", "sr"));
- public static final LinearUnit HERTZ = ONE.dividedBy(SECOND)
- .withName(NameSymbol.of("hertz", "Hz"));
- // for periodic phenomena
- public static final LinearUnit NEWTON = KILOGRAM.times(METRE)
- .dividedBy(SECOND.times(SECOND))
- .withName(NameSymbol.of("newton", "N"));
- public static final LinearUnit PASCAL = NEWTON.dividedBy(METRE.times(METRE))
- .withName(NameSymbol.of("pascal", "Pa"));
- public static final LinearUnit JOULE = NEWTON.times(METRE)
- .withName(NameSymbol.of("joule", "J"));
- public static final LinearUnit WATT = JOULE.dividedBy(SECOND)
- .withName(NameSymbol.of("watt", "W"));
- public static final LinearUnit COULOMB = AMPERE.times(SECOND)
- .withName(NameSymbol.of("coulomb", "C"));
- public static final LinearUnit VOLT = JOULE.dividedBy(COULOMB)
- .withName(NameSymbol.of("volt", "V"));
- public static final LinearUnit FARAD = COULOMB.dividedBy(VOLT)
- .withName(NameSymbol.of("farad", "F"));
- public static final LinearUnit OHM = VOLT.dividedBy(AMPERE)
- .withName(NameSymbol.of("ohm", "\u03A9")); // omega
- public static final LinearUnit SIEMENS = ONE.dividedBy(OHM)
- .withName(NameSymbol.of("siemens", "S"));
- public static final LinearUnit WEBER = VOLT.times(SECOND)
- .withName(NameSymbol.of("weber", "Wb"));
- public static final LinearUnit TESLA = WEBER.dividedBy(METRE.times(METRE))
- .withName(NameSymbol.of("tesla", "T"));
- public static final LinearUnit HENRY = WEBER.dividedBy(AMPERE)
- .withName(NameSymbol.of("henry", "H"));
- public static final LinearUnit LUMEN = CANDELA.times(STERADIAN)
- .withName(NameSymbol.of("lumen", "lm"));
- public static final LinearUnit LUX = LUMEN.dividedBy(METRE.times(METRE))
- .withName(NameSymbol.of("lux", "lx"));
- public static final LinearUnit BEQUEREL = ONE.dividedBy(SECOND)
- .withName(NameSymbol.of("bequerel", "Bq"));
- // for activity referred to a nucleotide
- public static final LinearUnit GRAY = JOULE.dividedBy(KILOGRAM)
- .withName(NameSymbol.of("grey", "Gy"));
- // for absorbed dose
- public static final LinearUnit SIEVERT = JOULE.dividedBy(KILOGRAM)
- .withName(NameSymbol.of("sievert", "Sv"));
- // for dose equivalent
- public static final LinearUnit KATAL = MOLE.dividedBy(SECOND)
- .withName(NameSymbol.of("katal", "kat"));
- // common derived units included for convenience
- public static final LinearUnit GRAM = KILOGRAM.dividedBy(1000)
- .withName(NameSymbol.of("gram", "g"));
-
- public static final LinearUnit SQUARE_METRE = METRE.toExponent(2)
- .withName(NameSymbol.of("square metre", "m^2", "square meter",
- "metre squared", "meter squared"));
- public static final LinearUnit CUBIC_METRE = METRE.toExponent(3)
- .withName(NameSymbol.of("cubic metre", "m^3", "cubic meter",
- "metre cubed", "meter cubed"));
- public static final LinearUnit METRE_PER_SECOND = METRE.dividedBy(SECOND)
- .withName(
- NameSymbol.of("metre per second", "m/s", "meter per second"));
- // Non-SI units included for convenience
- public static final Unit CELSIUS = Unit
- .fromConversionFunctions(KELVIN.getBase(), tempK -> tempK - 273.15,
- tempC -> tempC + 273.15)
- .withName(NameSymbol.of("degree Celsius", "\u00B0C"));
-
- public static final LinearUnit MINUTE = SECOND.times(60)
- .withName(NameSymbol.of("minute", "min"));
- public static final LinearUnit HOUR = MINUTE.times(60)
- .withName(NameSymbol.of("hour", "h", "hr"));
- public static final LinearUnit DAY = HOUR.times(60)
- .withName(NameSymbol.of("day", "d"));
- public static final LinearUnit KILOMETRE_PER_HOUR = METRE.times(1000)
- .dividedBy(HOUR).withName(NameSymbol.of("kilometre per hour", "km/h",
- "kilometer per hour"));
- public static final LinearUnit DEGREE = RADIAN.times(360 / (2 * Math.PI))
- .withName(NameSymbol.of("degree", "\u00B0", "deg"));
- public static final LinearUnit ARCMINUTE = DEGREE.dividedBy(60)
- .withName(NameSymbol.of("arcminute", "arcmin"));
- public static final LinearUnit ARCSECOND = ARCMINUTE.dividedBy(60)
- .withName(NameSymbol.of("arcsecond", "arcsec"));
- public static final LinearUnit ASTRONOMICAL_UNIT = METRE
- .times(149597870700.0)
- .withName(NameSymbol.of("astronomical unit", "au"));
- public static final LinearUnit PARSEC = ASTRONOMICAL_UNIT
- .dividedBy(ARCSECOND).withName(NameSymbol.of("parsec", "pc"));
- public static final LinearUnit HECTARE = METRE.times(METRE).times(10000.0)
- .withName(NameSymbol.of("hectare", "ha"));
- public static final LinearUnit LITRE = METRE.times(METRE).times(METRE)
- .dividedBy(1000.0).withName(NameSymbol.of("litre", "L", "l", "liter"));
- public static final LinearUnit TONNE = KILOGRAM.times(1000.0)
- .withName(NameSymbol.of("tonne", "t", "metric ton"));
- public static final LinearUnit DALTON = KILOGRAM.times(1.660539040e-27)
- .withName(NameSymbol.of("dalton", "Da", "atomic unit", "u")); // approximate
- // value
- public static final LinearUnit ELECTRONVOLT = JOULE.times(1.602176634e-19)
- .withName(NameSymbol.of("electron volt", "eV"));
- public static final LinearUnit BYTE = BIT.times(8)
- .withName(NameSymbol.of("byte", "B"));
- public static final Unit NEPER = Unit.fromConversionFunctions(ONE.getBase(),
- pr -> 0.5 * Math.log(pr), Np -> Math.exp(2 * Np))
- .withName(NameSymbol.of("neper", "Np"));
- public static final Unit BEL = Unit.fromConversionFunctions(ONE.getBase(),
- pr -> Math.log10(pr), dB -> Math.pow(10, dB))
- .withName(NameSymbol.of("bel", "B"));
- public static final Unit DECIBEL = Unit
- .fromConversionFunctions(ONE.getBase(), pr -> 10 * Math.log10(pr),
- dB -> Math.pow(10, dB / 10))
- .withName(NameSymbol.of("decibel", "dB"));
-
- /// The prefixes of the SI
- // expanding decimal prefixes
- public static final UnitPrefix KILO = UnitPrefix.valueOf(1e3)
- .withName(NameSymbol.of("kilo", "k", "K"));
- public static final UnitPrefix MEGA = UnitPrefix.valueOf(1e6)
- .withName(NameSymbol.of("mega", "M"));
- public static final UnitPrefix GIGA = UnitPrefix.valueOf(1e9)
- .withName(NameSymbol.of("giga", "G"));
- public static final UnitPrefix TERA = UnitPrefix.valueOf(1e12)
- .withName(NameSymbol.of("tera", "T"));
- public static final UnitPrefix PETA = UnitPrefix.valueOf(1e15)
- .withName(NameSymbol.of("peta", "P"));
- public static final UnitPrefix EXA = UnitPrefix.valueOf(1e18)
- .withName(NameSymbol.of("exa", "E"));
- public static final UnitPrefix ZETTA = UnitPrefix.valueOf(1e21)
- .withName(NameSymbol.of("zetta", "Z"));
- public static final UnitPrefix YOTTA = UnitPrefix.valueOf(1e24)
- .withName(NameSymbol.of("yotta", "Y"));
-
- // contracting decimal prefixes
- public static final UnitPrefix MILLI = UnitPrefix.valueOf(1e-3)
- .withName(NameSymbol.of("milli", "m"));
- public static final UnitPrefix MICRO = UnitPrefix.valueOf(1e-6)
- .withName(NameSymbol.of("micro", "\u03BC", "u")); // mu
- public static final UnitPrefix NANO = UnitPrefix.valueOf(1e-9)
- .withName(NameSymbol.of("nano", "n"));
- public static final UnitPrefix PICO = UnitPrefix.valueOf(1e-12)
- .withName(NameSymbol.of("pico", "p"));
- public static final UnitPrefix FEMTO = UnitPrefix.valueOf(1e-15)
- .withName(NameSymbol.of("femto", "f"));
- public static final UnitPrefix ATTO = UnitPrefix.valueOf(1e-18)
- .withName(NameSymbol.of("atto", "a"));
- public static final UnitPrefix ZEPTO = UnitPrefix.valueOf(1e-21)
- .withName(NameSymbol.of("zepto", "z"));
- public static final UnitPrefix YOCTO = UnitPrefix.valueOf(1e-24)
- .withName(NameSymbol.of("yocto", "y"));
-
- // prefixes that don't match the pattern of thousands
- public static final UnitPrefix DEKA = UnitPrefix.valueOf(1e1)
- .withName(NameSymbol.of("deka", "da", "deca", "D"));
- public static final UnitPrefix HECTO = UnitPrefix.valueOf(1e2)
- .withName(NameSymbol.of("hecto", "h", "H", "hekto"));
- public static final UnitPrefix DECI = UnitPrefix.valueOf(1e-1)
- .withName(NameSymbol.of("deci", "d"));
- public static final UnitPrefix CENTI = UnitPrefix.valueOf(1e-2)
- .withName(NameSymbol.of("centi", "c"));
- public static final UnitPrefix KIBI = UnitPrefix.valueOf(1024)
- .withName(NameSymbol.of("kibi", "Ki"));
- public static final UnitPrefix MEBI = KIBI.times(1024)
- .withName(NameSymbol.of("mebi", "Mi"));
- public static final UnitPrefix GIBI = MEBI.times(1024)
- .withName(NameSymbol.of("gibi", "Gi"));
- public static final UnitPrefix TEBI = GIBI.times(1024)
- .withName(NameSymbol.of("tebi", "Ti"));
- public static final UnitPrefix PEBI = TEBI.times(1024)
- .withName(NameSymbol.of("pebi", "Pi"));
- public static final UnitPrefix EXBI = PEBI.times(1024)
- .withName(NameSymbol.of("exbi", "Ei"));
-
- // a few prefixed units
- public static final LinearUnit MICROMETRE = SI.METRE.withPrefix(SI.MICRO);
- public static final LinearUnit MILLIMETRE = SI.METRE.withPrefix(SI.MILLI);
- public static final LinearUnit KILOMETRE = SI.METRE.withPrefix(SI.KILO);
- public static final LinearUnit MEGAMETRE = SI.METRE.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROLITRE = SI.LITRE.withPrefix(SI.MICRO);
- public static final LinearUnit MILLILITRE = SI.LITRE.withPrefix(SI.MILLI);
- public static final LinearUnit KILOLITRE = SI.LITRE.withPrefix(SI.KILO);
- public static final LinearUnit MEGALITRE = SI.LITRE.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROSECOND = SI.SECOND.withPrefix(SI.MICRO);
- public static final LinearUnit MILLISECOND = SI.SECOND.withPrefix(SI.MILLI);
- public static final LinearUnit KILOSECOND = SI.SECOND.withPrefix(SI.KILO);
- public static final LinearUnit MEGASECOND = SI.SECOND.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROGRAM = SI.GRAM.withPrefix(SI.MICRO);
- public static final LinearUnit MILLIGRAM = SI.GRAM.withPrefix(SI.MILLI);
- public static final LinearUnit MEGAGRAM = SI.GRAM.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICRONEWTON = SI.NEWTON.withPrefix(SI.MICRO);
- public static final LinearUnit MILLINEWTON = SI.NEWTON.withPrefix(SI.MILLI);
- public static final LinearUnit KILONEWTON = SI.NEWTON.withPrefix(SI.KILO);
- public static final LinearUnit MEGANEWTON = SI.NEWTON.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROJOULE = SI.JOULE.withPrefix(SI.MICRO);
- public static final LinearUnit MILLIJOULE = SI.JOULE.withPrefix(SI.MILLI);
- public static final LinearUnit KILOJOULE = SI.JOULE.withPrefix(SI.KILO);
- public static final LinearUnit MEGAJOULE = SI.JOULE.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROWATT = SI.WATT.withPrefix(SI.MICRO);
- public static final LinearUnit MILLIWATT = SI.WATT.withPrefix(SI.MILLI);
- public static final LinearUnit KILOWATT = SI.WATT.withPrefix(SI.KILO);
- public static final LinearUnit MEGAWATT = SI.WATT.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROCOULOMB = SI.COULOMB
- .withPrefix(SI.MICRO);
- public static final LinearUnit MILLICOULOMB = SI.COULOMB
- .withPrefix(SI.MILLI);
- public static final LinearUnit KILOCOULOMB = SI.COULOMB.withPrefix(SI.KILO);
- public static final LinearUnit MEGACOULOMB = SI.COULOMB.withPrefix(SI.MEGA);
-
- public static final LinearUnit MICROAMPERE = SI.AMPERE.withPrefix(SI.MICRO);
- public static final LinearUnit MILLIAMPERE = SI.AMPERE.withPrefix(SI.MILLI);
-
- public static final LinearUnit MICROVOLT = SI.VOLT.withPrefix(SI.MICRO);
- public static final LinearUnit MILLIVOLT = SI.VOLT.withPrefix(SI.MILLI);
- public static final LinearUnit KILOVOLT = SI.VOLT.withPrefix(SI.KILO);
- public static final LinearUnit MEGAVOLT = SI.VOLT.withPrefix(SI.MEGA);
-
- public static final LinearUnit KILOOHM = SI.OHM.withPrefix(SI.KILO);
- public static final LinearUnit MEGAOHM = SI.OHM.withPrefix(SI.MEGA);
-
- // sets of prefixes
- public static final Set<UnitPrefix> ALL_PREFIXES = Set.of(DEKA, HECTO, KILO,
- MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, DECI, CENTI, MILLI, MICRO,
- NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO, KIBI, MEBI, GIBI, TEBI, PEBI,
- EXBI);
-
- public static final Set<UnitPrefix> DECIMAL_PREFIXES = Set.of(DEKA, HECTO,
- KILO, MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, DECI, CENTI, MILLI,
- MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO);
- public static final Set<UnitPrefix> THOUSAND_PREFIXES = Set.of(KILO, MEGA,
- GIGA, TERA, PETA, EXA, ZETTA, YOTTA, MILLI, MICRO, NANO, PICO, FEMTO,
- ATTO, ZEPTO, YOCTO);
- public static final Set<UnitPrefix> MAGNIFYING_PREFIXES = Set.of(DEKA, HECTO,
- KILO, MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, KIBI, MEBI, GIBI,
- TEBI, PEBI, EXBI);
- public static final Set<UnitPrefix> REDUCING_PREFIXES = Set.of(DECI, CENTI,
- MILLI, MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO);
-
- // You may NOT get SI instances!
- private SI() {
- throw new AssertionError();
- }
-}
+/**
+ * Copyright (C) 2018 Adrien Hopkins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.unitConverter.unit;
+
+import java.util.Set;
+
+import org.unitConverter.math.ObjectProduct;
+
+/**
+ * All of the units, prefixes and dimensions that are used by the SI, as well as
+ * some outside the SI.
+ *
+ * <p>
+ * This class does not include prefixed units. To obtain prefixed units, use
+ * {@link LinearUnit#withPrefix}:
+ *
+ * <pre>
+ * LinearUnit KILOMETRE = SI.METRE.withPrefix(SI.KILO);
+ * </pre>
+ *
+ *
+ * @author Adrien Hopkins
+ * @since 2019-10-16
+ */
+public final class SI {
+ /// dimensions used by SI units
+ // base dimensions, as BaseDimensions
+ public static final class BaseDimensions {
+ public static final BaseDimension LENGTH = BaseDimension.valueOf("Length",
+ "L");
+ public static final BaseDimension MASS = BaseDimension.valueOf("Mass",
+ "M");
+ public static final BaseDimension TIME = BaseDimension.valueOf("Time",
+ "T");
+ public static final BaseDimension ELECTRIC_CURRENT = BaseDimension
+ .valueOf("Electric Current", "I");
+ public static final BaseDimension TEMPERATURE = BaseDimension
+ .valueOf("Temperature", "\u0398"); // theta symbol
+ public static final BaseDimension QUANTITY = BaseDimension
+ .valueOf("Quantity", "N");
+ public static final BaseDimension LUMINOUS_INTENSITY = BaseDimension
+ .valueOf("Luminous Intensity", "J");
+ public static final BaseDimension INFORMATION = BaseDimension
+ .valueOf("Information", "Info"); // non-SI
+ public static final BaseDimension CURRENCY = BaseDimension
+ .valueOf("Currency", "$$"); // non-SI
+
+ // You may NOT get SI.BaseDimensions instances!
+ private BaseDimensions() {
+ throw new AssertionError();
+ }
+ }
+
+ /// base units of the SI
+ // suppressing warnings since these are the same object, but in a different
+ /// form (class)
+ @SuppressWarnings("hiding")
+ public static final class BaseUnits {
+ public static final BaseUnit METRE = BaseUnit
+ .valueOf(BaseDimensions.LENGTH, "metre", "m");
+ public static final BaseUnit KILOGRAM = BaseUnit
+ .valueOf(BaseDimensions.MASS, "kilogram", "kg");
+ public static final BaseUnit SECOND = BaseUnit
+ .valueOf(BaseDimensions.TIME, "second", "s");
+ public static final BaseUnit AMPERE = BaseUnit
+ .valueOf(BaseDimensions.ELECTRIC_CURRENT, "ampere", "A");
+ public static final BaseUnit KELVIN = BaseUnit
+ .valueOf(BaseDimensions.TEMPERATURE, "kelvin", "K");
+ public static final BaseUnit MOLE = BaseUnit
+ .valueOf(BaseDimensions.QUANTITY, "mole", "mol");
+ public static final BaseUnit CANDELA = BaseUnit
+ .valueOf(BaseDimensions.LUMINOUS_INTENSITY, "candela", "cd");
+ public static final BaseUnit BIT = BaseUnit
+ .valueOf(BaseDimensions.INFORMATION, "bit", "b");
+ public static final BaseUnit DOLLAR = BaseUnit
+ .valueOf(BaseDimensions.CURRENCY, "dollar", "$");
+
+ public static final Set<BaseUnit> BASE_UNITS = Set.of(METRE, KILOGRAM,
+ SECOND, AMPERE, KELVIN, MOLE, CANDELA, BIT);
+
+ // You may NOT get SI.BaseUnits instances!
+ private BaseUnits() {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Constants that relate to the SI or other systems.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-11-08
+ */
+ public static final class Constants {
+ public static final LinearUnit EARTH_GRAVITY = METRE.dividedBy(SECOND)
+ .dividedBy(SECOND).times(9.80665);
+ }
+
+ // dimensions used in the SI, as ObjectProducts
+ public static final class Dimensions {
+ public static final ObjectProduct<BaseDimension> EMPTY = ObjectProduct
+ .empty();
+ public static final ObjectProduct<BaseDimension> LENGTH = ObjectProduct
+ .oneOf(BaseDimensions.LENGTH);
+ public static final ObjectProduct<BaseDimension> MASS = ObjectProduct
+ .oneOf(BaseDimensions.MASS);
+ public static final ObjectProduct<BaseDimension> TIME = ObjectProduct
+ .oneOf(BaseDimensions.TIME);
+ public static final ObjectProduct<BaseDimension> ELECTRIC_CURRENT = ObjectProduct
+ .oneOf(BaseDimensions.ELECTRIC_CURRENT);
+ public static final ObjectProduct<BaseDimension> TEMPERATURE = ObjectProduct
+ .oneOf(BaseDimensions.TEMPERATURE);
+ public static final ObjectProduct<BaseDimension> QUANTITY = ObjectProduct
+ .oneOf(BaseDimensions.QUANTITY);
+ public static final ObjectProduct<BaseDimension> LUMINOUS_INTENSITY = ObjectProduct
+ .oneOf(BaseDimensions.LUMINOUS_INTENSITY);
+ public static final ObjectProduct<BaseDimension> INFORMATION = ObjectProduct
+ .oneOf(BaseDimensions.INFORMATION);
+ public static final ObjectProduct<BaseDimension> CURRENCY = ObjectProduct
+ .oneOf(BaseDimensions.CURRENCY);
+
+ // derived dimensions without named SI units
+ public static final ObjectProduct<BaseDimension> AREA = LENGTH
+ .times(LENGTH);
+ public static final ObjectProduct<BaseDimension> VOLUME = AREA
+ .times(LENGTH);
+ public static final ObjectProduct<BaseDimension> VELOCITY = LENGTH
+ .dividedBy(TIME);
+ public static final ObjectProduct<BaseDimension> ACCELERATION = VELOCITY
+ .dividedBy(TIME);
+ public static final ObjectProduct<BaseDimension> WAVENUMBER = EMPTY
+ .dividedBy(LENGTH);
+ public static final ObjectProduct<BaseDimension> MASS_DENSITY = MASS
+ .dividedBy(VOLUME);
+ public static final ObjectProduct<BaseDimension> SURFACE_DENSITY = MASS
+ .dividedBy(AREA);
+ public static final ObjectProduct<BaseDimension> SPECIFIC_VOLUME = VOLUME
+ .dividedBy(MASS);
+ public static final ObjectProduct<BaseDimension> CURRENT_DENSITY = ELECTRIC_CURRENT
+ .dividedBy(AREA);
+ public static final ObjectProduct<BaseDimension> MAGNETIC_FIELD_STRENGTH = ELECTRIC_CURRENT
+ .dividedBy(LENGTH);
+ public static final ObjectProduct<BaseDimension> CONCENTRATION = QUANTITY
+ .dividedBy(VOLUME);
+ public static final ObjectProduct<BaseDimension> MASS_CONCENTRATION = CONCENTRATION
+ .times(MASS);
+ public static final ObjectProduct<BaseDimension> LUMINANCE = LUMINOUS_INTENSITY
+ .dividedBy(AREA);
+ public static final ObjectProduct<BaseDimension> REFRACTIVE_INDEX = VELOCITY
+ .dividedBy(VELOCITY);
+ public static final ObjectProduct<BaseDimension> REFRACTIVE_PERMEABILITY = EMPTY
+ .times(EMPTY);
+ public static final ObjectProduct<BaseDimension> ANGLE = LENGTH
+ .dividedBy(LENGTH);
+ public static final ObjectProduct<BaseDimension> SOLID_ANGLE = AREA
+ .dividedBy(AREA);
+
+ // derived dimensions with named SI units
+ public static final ObjectProduct<BaseDimension> FREQUENCY = EMPTY
+ .dividedBy(TIME);
+ public static final ObjectProduct<BaseDimension> FORCE = MASS
+ .times(ACCELERATION);
+ public static final ObjectProduct<BaseDimension> ENERGY = FORCE
+ .times(LENGTH);
+ public static final ObjectProduct<BaseDimension> POWER = ENERGY
+ .dividedBy(TIME);
+ public static final ObjectProduct<BaseDimension> ELECTRIC_CHARGE = ELECTRIC_CURRENT
+ .times(TIME);
+ public static final ObjectProduct<BaseDimension> VOLTAGE = ENERGY
+ .dividedBy(ELECTRIC_CHARGE);
+ public static final ObjectProduct<BaseDimension> CAPACITANCE = ELECTRIC_CHARGE
+ .dividedBy(VOLTAGE);
+ public static final ObjectProduct<BaseDimension> ELECTRIC_RESISTANCE = VOLTAGE
+ .dividedBy(ELECTRIC_CURRENT);
+ public static final ObjectProduct<BaseDimension> ELECTRIC_CONDUCTANCE = ELECTRIC_CURRENT
+ .dividedBy(VOLTAGE);
+ public static final ObjectProduct<BaseDimension> MAGNETIC_FLUX = VOLTAGE
+ .times(TIME);
+ public static final ObjectProduct<BaseDimension> MAGNETIC_FLUX_DENSITY = MAGNETIC_FLUX
+ .dividedBy(AREA);
+ public static final ObjectProduct<BaseDimension> INDUCTANCE = MAGNETIC_FLUX
+ .dividedBy(ELECTRIC_CURRENT);
+ public static final ObjectProduct<BaseDimension> LUMINOUS_FLUX = LUMINOUS_INTENSITY
+ .times(SOLID_ANGLE);
+ public static final ObjectProduct<BaseDimension> ILLUMINANCE = LUMINOUS_FLUX
+ .dividedBy(AREA);
+ public static final ObjectProduct<BaseDimension> SPECIFIC_ENERGY = ENERGY
+ .dividedBy(MASS);
+ public static final ObjectProduct<BaseDimension> CATALYTIC_ACTIVITY = QUANTITY
+ .dividedBy(TIME);
+
+ // You may NOT get SI.Dimension instances!
+ private Dimensions() {
+ throw new AssertionError();
+ }
+ }
+
+ /// The units of the SI
+ public static final LinearUnit ONE = LinearUnit
+ .valueOf(ObjectProduct.empty(), 1);
+
+ public static final LinearUnit METRE = BaseUnits.METRE.asLinearUnit()
+ .withName(NameSymbol.of("metre", "m", "meter"));
+ public static final LinearUnit KILOGRAM = BaseUnits.KILOGRAM.asLinearUnit()
+ .withName(NameSymbol.of("kilogram", "kg"));
+ public static final LinearUnit SECOND = BaseUnits.SECOND.asLinearUnit()
+ .withName(NameSymbol.of("second", "s", "sec"));
+ public static final LinearUnit AMPERE = BaseUnits.AMPERE.asLinearUnit()
+ .withName(NameSymbol.of("ampere", "A"));
+ public static final LinearUnit KELVIN = BaseUnits.KELVIN.asLinearUnit()
+ .withName(NameSymbol.of("kelvin", "K"));
+ public static final LinearUnit MOLE = BaseUnits.MOLE.asLinearUnit()
+ .withName(NameSymbol.of("mole", "mol"));
+ public static final LinearUnit CANDELA = BaseUnits.CANDELA.asLinearUnit()
+ .withName(NameSymbol.of("candela", "cd"));
+ public static final LinearUnit BIT = BaseUnits.BIT.asLinearUnit()
+ .withName(NameSymbol.of("bit", "b"));
+ public static final LinearUnit DOLLAR = BaseUnits.DOLLAR.asLinearUnit()
+ .withName(NameSymbol.of("dollar", "$"));
+ // Non-base units
+ public static final LinearUnit RADIAN = METRE.dividedBy(METRE)
+ .withName(NameSymbol.of("radian", "rad"));
+
+ public static final LinearUnit STERADIAN = RADIAN.times(RADIAN)
+ .withName(NameSymbol.of("steradian", "sr"));
+ public static final LinearUnit HERTZ = ONE.dividedBy(SECOND)
+ .withName(NameSymbol.of("hertz", "Hz"));
+ // for periodic phenomena
+ public static final LinearUnit NEWTON = KILOGRAM.times(METRE)
+ .dividedBy(SECOND.times(SECOND))
+ .withName(NameSymbol.of("newton", "N"));
+ public static final LinearUnit PASCAL = NEWTON.dividedBy(METRE.times(METRE))
+ .withName(NameSymbol.of("pascal", "Pa"));
+ public static final LinearUnit JOULE = NEWTON.times(METRE)
+ .withName(NameSymbol.of("joule", "J"));
+ public static final LinearUnit WATT = JOULE.dividedBy(SECOND)
+ .withName(NameSymbol.of("watt", "W"));
+ public static final LinearUnit COULOMB = AMPERE.times(SECOND)
+ .withName(NameSymbol.of("coulomb", "C"));
+ public static final LinearUnit VOLT = JOULE.dividedBy(COULOMB)
+ .withName(NameSymbol.of("volt", "V"));
+ public static final LinearUnit FARAD = COULOMB.dividedBy(VOLT)
+ .withName(NameSymbol.of("farad", "F"));
+ public static final LinearUnit OHM = VOLT.dividedBy(AMPERE)
+ .withName(NameSymbol.of("ohm", "\u03A9")); // omega
+ public static final LinearUnit SIEMENS = ONE.dividedBy(OHM)
+ .withName(NameSymbol.of("siemens", "S"));
+ public static final LinearUnit WEBER = VOLT.times(SECOND)
+ .withName(NameSymbol.of("weber", "Wb"));
+ public static final LinearUnit TESLA = WEBER.dividedBy(METRE.times(METRE))
+ .withName(NameSymbol.of("tesla", "T"));
+ public static final LinearUnit HENRY = WEBER.dividedBy(AMPERE)
+ .withName(NameSymbol.of("henry", "H"));
+ public static final LinearUnit LUMEN = CANDELA.times(STERADIAN)
+ .withName(NameSymbol.of("lumen", "lm"));
+ public static final LinearUnit LUX = LUMEN.dividedBy(METRE.times(METRE))
+ .withName(NameSymbol.of("lux", "lx"));
+ public static final LinearUnit BEQUEREL = ONE.dividedBy(SECOND)
+ .withName(NameSymbol.of("bequerel", "Bq"));
+ // for activity referred to a nucleotide
+ public static final LinearUnit GRAY = JOULE.dividedBy(KILOGRAM)
+ .withName(NameSymbol.of("grey", "Gy"));
+ // for absorbed dose
+ public static final LinearUnit SIEVERT = JOULE.dividedBy(KILOGRAM)
+ .withName(NameSymbol.of("sievert", "Sv"));
+ // for dose equivalent
+ public static final LinearUnit KATAL = MOLE.dividedBy(SECOND)
+ .withName(NameSymbol.of("katal", "kat"));
+ // common derived units included for convenience
+ public static final LinearUnit GRAM = KILOGRAM.dividedBy(1000)
+ .withName(NameSymbol.of("gram", "g"));
+
+ public static final LinearUnit SQUARE_METRE = METRE.toExponent(2)
+ .withName(NameSymbol.of("square metre", "m^2", "square meter",
+ "metre squared", "meter squared"));
+ public static final LinearUnit CUBIC_METRE = METRE.toExponent(3)
+ .withName(NameSymbol.of("cubic metre", "m^3", "cubic meter",
+ "metre cubed", "meter cubed"));
+ public static final LinearUnit METRE_PER_SECOND = METRE.dividedBy(SECOND)
+ .withName(
+ NameSymbol.of("metre per second", "m/s", "meter per second"));
+ // Non-SI units included for convenience
+ public static final Unit CELSIUS = Unit
+ .fromConversionFunctions(KELVIN.getBase(), tempK -> tempK - 273.15,
+ tempC -> tempC + 273.15)
+ .withName(NameSymbol.of("degree Celsius", "\u00B0C"));
+
+ public static final LinearUnit MINUTE = SECOND.times(60)
+ .withName(NameSymbol.of("minute", "min"));
+ public static final LinearUnit HOUR = MINUTE.times(60)
+ .withName(NameSymbol.of("hour", "h", "hr"));
+ public static final LinearUnit DAY = HOUR.times(60)
+ .withName(NameSymbol.of("day", "d"));
+ public static final LinearUnit KILOMETRE_PER_HOUR = METRE.times(1000)
+ .dividedBy(HOUR).withName(NameSymbol.of("kilometre per hour", "km/h",
+ "kilometer per hour"));
+ public static final LinearUnit DEGREE = RADIAN.times(360 / (2 * Math.PI))
+ .withName(NameSymbol.of("degree", "\u00B0", "deg"));
+ public static final LinearUnit ARCMINUTE = DEGREE.dividedBy(60)
+ .withName(NameSymbol.of("arcminute", "arcmin"));
+ public static final LinearUnit ARCSECOND = ARCMINUTE.dividedBy(60)
+ .withName(NameSymbol.of("arcsecond", "arcsec"));
+ public static final LinearUnit ASTRONOMICAL_UNIT = METRE
+ .times(149597870700.0)
+ .withName(NameSymbol.of("astronomical unit", "au"));
+ public static final LinearUnit PARSEC = ASTRONOMICAL_UNIT
+ .dividedBy(ARCSECOND).withName(NameSymbol.of("parsec", "pc"));
+ public static final LinearUnit HECTARE = METRE.times(METRE).times(10000.0)
+ .withName(NameSymbol.of("hectare", "ha"));
+ public static final LinearUnit LITRE = METRE.times(METRE).times(METRE)
+ .dividedBy(1000.0).withName(NameSymbol.of("litre", "L", "l", "liter"));
+ public static final LinearUnit TONNE = KILOGRAM.times(1000.0)
+ .withName(NameSymbol.of("tonne", "t", "metric ton"));
+ public static final LinearUnit DALTON = KILOGRAM.times(1.660539040e-27)
+ .withName(NameSymbol.of("dalton", "Da", "atomic unit", "u")); // approximate
+ // value
+ public static final LinearUnit ELECTRONVOLT = JOULE.times(1.602176634e-19)
+ .withName(NameSymbol.of("electron volt", "eV"));
+ public static final LinearUnit BYTE = BIT.times(8)
+ .withName(NameSymbol.of("byte", "B"));
+ public static final Unit NEPER = Unit.fromConversionFunctions(ONE.getBase(),
+ pr -> 0.5 * Math.log(pr), Np -> Math.exp(2 * Np))
+ .withName(NameSymbol.of("neper", "Np"));
+ public static final Unit BEL = Unit.fromConversionFunctions(ONE.getBase(),
+ pr -> Math.log10(pr), dB -> Math.pow(10, dB))
+ .withName(NameSymbol.of("bel", "B"));
+ public static final Unit DECIBEL = Unit
+ .fromConversionFunctions(ONE.getBase(), pr -> 10 * Math.log10(pr),
+ dB -> Math.pow(10, dB / 10))
+ .withName(NameSymbol.of("decibel", "dB"));
+
+ /// The prefixes of the SI
+ // expanding decimal prefixes
+ public static final UnitPrefix KILO = UnitPrefix.valueOf(1e3)
+ .withName(NameSymbol.of("kilo", "k", "K"));
+ public static final UnitPrefix MEGA = UnitPrefix.valueOf(1e6)
+ .withName(NameSymbol.of("mega", "M"));
+ public static final UnitPrefix GIGA = UnitPrefix.valueOf(1e9)
+ .withName(NameSymbol.of("giga", "G"));
+ public static final UnitPrefix TERA = UnitPrefix.valueOf(1e12)
+ .withName(NameSymbol.of("tera", "T"));
+ public static final UnitPrefix PETA = UnitPrefix.valueOf(1e15)
+ .withName(NameSymbol.of("peta", "P"));
+ public static final UnitPrefix EXA = UnitPrefix.valueOf(1e18)
+ .withName(NameSymbol.of("exa", "E"));
+ public static final UnitPrefix ZETTA = UnitPrefix.valueOf(1e21)
+ .withName(NameSymbol.of("zetta", "Z"));
+ public static final UnitPrefix YOTTA = UnitPrefix.valueOf(1e24)
+ .withName(NameSymbol.of("yotta", "Y"));
+
+ // contracting decimal prefixes
+ public static final UnitPrefix MILLI = UnitPrefix.valueOf(1e-3)
+ .withName(NameSymbol.of("milli", "m"));
+ public static final UnitPrefix MICRO = UnitPrefix.valueOf(1e-6)
+ .withName(NameSymbol.of("micro", "\u03BC", "u")); // mu
+ public static final UnitPrefix NANO = UnitPrefix.valueOf(1e-9)
+ .withName(NameSymbol.of("nano", "n"));
+ public static final UnitPrefix PICO = UnitPrefix.valueOf(1e-12)
+ .withName(NameSymbol.of("pico", "p"));
+ public static final UnitPrefix FEMTO = UnitPrefix.valueOf(1e-15)
+ .withName(NameSymbol.of("femto", "f"));
+ public static final UnitPrefix ATTO = UnitPrefix.valueOf(1e-18)
+ .withName(NameSymbol.of("atto", "a"));
+ public static final UnitPrefix ZEPTO = UnitPrefix.valueOf(1e-21)
+ .withName(NameSymbol.of("zepto", "z"));
+ public static final UnitPrefix YOCTO = UnitPrefix.valueOf(1e-24)
+ .withName(NameSymbol.of("yocto", "y"));
+
+ // prefixes that don't match the pattern of thousands
+ public static final UnitPrefix DEKA = UnitPrefix.valueOf(1e1)
+ .withName(NameSymbol.of("deka", "da", "deca", "D"));
+ public static final UnitPrefix HECTO = UnitPrefix.valueOf(1e2)
+ .withName(NameSymbol.of("hecto", "h", "H", "hekto"));
+ public static final UnitPrefix DECI = UnitPrefix.valueOf(1e-1)
+ .withName(NameSymbol.of("deci", "d"));
+ public static final UnitPrefix CENTI = UnitPrefix.valueOf(1e-2)
+ .withName(NameSymbol.of("centi", "c"));
+ public static final UnitPrefix KIBI = UnitPrefix.valueOf(1024)
+ .withName(NameSymbol.of("kibi", "Ki"));
+ public static final UnitPrefix MEBI = KIBI.times(1024)
+ .withName(NameSymbol.of("mebi", "Mi"));
+ public static final UnitPrefix GIBI = MEBI.times(1024)
+ .withName(NameSymbol.of("gibi", "Gi"));
+ public static final UnitPrefix TEBI = GIBI.times(1024)
+ .withName(NameSymbol.of("tebi", "Ti"));
+ public static final UnitPrefix PEBI = TEBI.times(1024)
+ .withName(NameSymbol.of("pebi", "Pi"));
+ public static final UnitPrefix EXBI = PEBI.times(1024)
+ .withName(NameSymbol.of("exbi", "Ei"));
+
+ // a few prefixed units
+ public static final LinearUnit MICROMETRE = SI.METRE.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLIMETRE = SI.METRE.withPrefix(SI.MILLI);
+ public static final LinearUnit KILOMETRE = SI.METRE.withPrefix(SI.KILO);
+ public static final LinearUnit MEGAMETRE = SI.METRE.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROLITRE = SI.LITRE.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLILITRE = SI.LITRE.withPrefix(SI.MILLI);
+ public static final LinearUnit KILOLITRE = SI.LITRE.withPrefix(SI.KILO);
+ public static final LinearUnit MEGALITRE = SI.LITRE.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROSECOND = SI.SECOND.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLISECOND = SI.SECOND.withPrefix(SI.MILLI);
+ public static final LinearUnit KILOSECOND = SI.SECOND.withPrefix(SI.KILO);
+ public static final LinearUnit MEGASECOND = SI.SECOND.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROGRAM = SI.GRAM.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLIGRAM = SI.GRAM.withPrefix(SI.MILLI);
+ public static final LinearUnit MEGAGRAM = SI.GRAM.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICRONEWTON = SI.NEWTON.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLINEWTON = SI.NEWTON.withPrefix(SI.MILLI);
+ public static final LinearUnit KILONEWTON = SI.NEWTON.withPrefix(SI.KILO);
+ public static final LinearUnit MEGANEWTON = SI.NEWTON.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROJOULE = SI.JOULE.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLIJOULE = SI.JOULE.withPrefix(SI.MILLI);
+ public static final LinearUnit KILOJOULE = SI.JOULE.withPrefix(SI.KILO);
+ public static final LinearUnit MEGAJOULE = SI.JOULE.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROWATT = SI.WATT.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLIWATT = SI.WATT.withPrefix(SI.MILLI);
+ public static final LinearUnit KILOWATT = SI.WATT.withPrefix(SI.KILO);
+ public static final LinearUnit MEGAWATT = SI.WATT.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROCOULOMB = SI.COULOMB
+ .withPrefix(SI.MICRO);
+ public static final LinearUnit MILLICOULOMB = SI.COULOMB
+ .withPrefix(SI.MILLI);
+ public static final LinearUnit KILOCOULOMB = SI.COULOMB.withPrefix(SI.KILO);
+ public static final LinearUnit MEGACOULOMB = SI.COULOMB.withPrefix(SI.MEGA);
+
+ public static final LinearUnit MICROAMPERE = SI.AMPERE.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLIAMPERE = SI.AMPERE.withPrefix(SI.MILLI);
+
+ public static final LinearUnit MICROVOLT = SI.VOLT.withPrefix(SI.MICRO);
+ public static final LinearUnit MILLIVOLT = SI.VOLT.withPrefix(SI.MILLI);
+ public static final LinearUnit KILOVOLT = SI.VOLT.withPrefix(SI.KILO);
+ public static final LinearUnit MEGAVOLT = SI.VOLT.withPrefix(SI.MEGA);
+
+ public static final LinearUnit KILOOHM = SI.OHM.withPrefix(SI.KILO);
+ public static final LinearUnit MEGAOHM = SI.OHM.withPrefix(SI.MEGA);
+
+ // sets of prefixes
+ public static final Set<UnitPrefix> ALL_PREFIXES = Set.of(DEKA, HECTO, KILO,
+ MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, DECI, CENTI, MILLI, MICRO,
+ NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO, KIBI, MEBI, GIBI, TEBI, PEBI,
+ EXBI);
+
+ public static final Set<UnitPrefix> DECIMAL_PREFIXES = Set.of(DEKA, HECTO,
+ KILO, MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, DECI, CENTI, MILLI,
+ MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO);
+ public static final Set<UnitPrefix> THOUSAND_PREFIXES = Set.of(KILO, MEGA,
+ GIGA, TERA, PETA, EXA, ZETTA, YOTTA, MILLI, MICRO, NANO, PICO, FEMTO,
+ ATTO, ZEPTO, YOCTO);
+ public static final Set<UnitPrefix> MAGNIFYING_PREFIXES = Set.of(DEKA, HECTO,
+ KILO, MEGA, GIGA, TERA, PETA, EXA, ZETTA, YOTTA, KIBI, MEBI, GIBI,
+ TEBI, PEBI, EXBI);
+ public static final Set<UnitPrefix> REDUCING_PREFIXES = Set.of(DECI, CENTI,
+ MILLI, MICRO, NANO, PICO, FEMTO, ATTO, ZEPTO, YOCTO);
+
+ // You may NOT get SI instances!
+ private SI() {
+ throw new AssertionError();
+ }
+}
diff --git a/src/org/unitConverter/unit/USCustomary.java b/src/main/java/org/unitConverter/unit/USCustomary.java
index 1c4bcfe..1c4bcfe 100644
--- a/src/org/unitConverter/unit/USCustomary.java
+++ b/src/main/java/org/unitConverter/unit/USCustomary.java
diff --git a/src/org/unitConverter/unit/Unit.java b/src/main/java/org/unitConverter/unit/Unit.java
index 0a3298f..0a3298f 100644
--- a/src/org/unitConverter/unit/Unit.java
+++ b/src/main/java/org/unitConverter/unit/Unit.java
diff --git a/src/org/unitConverter/unit/UnitDatabase.java b/src/main/java/org/unitConverter/unit/UnitDatabase.java
index 000acf5..6322fef 100644
--- a/src/org/unitConverter/unit/UnitDatabase.java
+++ b/src/main/java/org/unitConverter/unit/UnitDatabase.java
@@ -18,6 +18,7 @@ package org.unitConverter.unit;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -34,6 +35,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Scanner;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -1880,6 +1882,22 @@ public final class UnitDatabase {
}
/**
+ * Adds all dimensions from a {@code InputStream}. Otherwise, works like
+ * {@link #loadDimensionFile}.
+ *
+ * @param stream stream to load from
+ * @since 2021-03-27
+ */
+ public void loadDimensionsFromStream(final InputStream stream) {
+ try (final Scanner scanner = new Scanner(stream)) {
+ long lineCounter = 0;
+ while (scanner.hasNextLine()) {
+ this.addDimensionFromLine(scanner.nextLine(), ++lineCounter);
+ }
+ }
+ }
+
+ /**
* Adds all units from a file, using data from the database to parse them.
* <p>
* Each line in the file should consist of a name and an expression (parsed
@@ -1919,6 +1937,22 @@ public final class UnitDatabase {
}
/**
+ * Adds all units from a {@code InputStream}. Otherwise, works like
+ * {@link #loadUnitsFile}.
+ *
+ * @param stream stream to load from
+ * @since 2021-03-27
+ */
+ public void loadUnitsFromStream(InputStream stream) {
+ try (final Scanner scanner = new Scanner(stream)) {
+ long lineCounter = 0;
+ while (scanner.hasNextLine()) {
+ this.addUnitOrPrefixFromLine(scanner.nextLine(), ++lineCounter);
+ }
+ }
+ }
+
+ /**
* @return a map mapping prefix names to prefixes
* @since 2019-04-13
* @since v0.2.0
diff --git a/src/org/unitConverter/unit/UnitPrefix.java b/src/main/java/org/unitConverter/unit/UnitPrefix.java
index 31cc0b3..31cc0b3 100644
--- a/src/org/unitConverter/unit/UnitPrefix.java
+++ b/src/main/java/org/unitConverter/unit/UnitPrefix.java
diff --git a/src/org/unitConverter/unit/UnitValue.java b/src/main/java/org/unitConverter/unit/UnitValue.java
index c138332..c138332 100644
--- a/src/org/unitConverter/unit/UnitValue.java
+++ b/src/main/java/org/unitConverter/unit/UnitValue.java
diff --git a/src/org/unitConverter/unit/Unitlike.java b/src/main/java/org/unitConverter/unit/Unitlike.java
index 8077771..8077771 100644
--- a/src/org/unitConverter/unit/Unitlike.java
+++ b/src/main/java/org/unitConverter/unit/Unitlike.java
diff --git a/src/org/unitConverter/unit/UnitlikeValue.java b/src/main/java/org/unitConverter/unit/UnitlikeValue.java
index 79201c4..79201c4 100644
--- a/src/org/unitConverter/unit/UnitlikeValue.java
+++ b/src/main/java/org/unitConverter/unit/UnitlikeValue.java
diff --git a/src/org/unitConverter/unit/package-info.java b/src/main/java/org/unitConverter/unit/package-info.java
index 2f0e097..2f0e097 100644
--- a/src/org/unitConverter/unit/package-info.java
+++ b/src/main/java/org/unitConverter/unit/package-info.java
diff --git a/src/about.txt b/src/main/resources/about.txt
index 1bad9e8..1bad9e8 100644
--- a/src/about.txt
+++ b/src/main/resources/about.txt
diff --git a/src/main/resources/dimensionfile.txt b/src/main/resources/dimensionfile.txt
new file mode 100644
index 0000000..3485de5
--- /dev/null
+++ b/src/main/resources/dimensionfile.txt
@@ -0,0 +1,18 @@
+# A file for the unit dimensions in my unit converter program
+
+# SI Base Dimensions
+# ! means "look for an existing dimension which I will load at the start"
+# This is necessary because every dimension must be defined by others, and I need somewhere to start.
+
+# I have excluded electric current, quantity and luminous intensity since their units are exclusively SI.
+
+LENGTH !
+MASS !
+TIME !
+TEMPERATURE !
+
+# Derived Dimensions
+AREA LENGTH^2
+VOLUME LENGTH^3
+VELOCITY LENGTH / TIME
+ENERGY MASS * VELOCITY^2 \ No newline at end of file
diff --git a/src/main/resources/metric_exceptions.txt b/src/main/resources/metric_exceptions.txt
new file mode 100644
index 0000000..73748c0
--- /dev/null
+++ b/src/main/resources/metric_exceptions.txt
@@ -0,0 +1,19 @@
+# This is a list of exceptions for the one-way conversion mode
+# Units in this list will be included in both From: and To:
+# regardless of whether or not one-way conversion is enabled.
+
+tempC
+tempCelsius
+s
+second
+min
+minute
+h
+hour
+d
+day
+wk
+week
+gregorianmonth
+gregorianyear
+km/h \ No newline at end of file
diff --git a/src/main/resources/unitsfile.txt b/src/main/resources/unitsfile.txt
new file mode 100644
index 0000000..eafe885
--- /dev/null
+++ b/src/main/resources/unitsfile.txt
@@ -0,0 +1,267 @@
+# A file for the units in my unit converter program
+
+# SI Base Units
+# ! means "look for an existing unit which I will load at the start"
+# This is necessary because every unit must be defined by others, and I need somewhere to start.
+
+metre !
+kilogram !
+second !
+ampere !
+kelvin !
+mole !
+candela !
+
+# Symbols and aliases for base units
+
+meter metre
+m metre
+kg kilogram
+s second
+A ampere
+K kelvin
+mol mole
+cd candela
+
+# the bit and byte, units of information
+
+bit !
+b bit
+byte 8 bit
+B byte
+
+# SI prefixes
+
+deca- 10
+deka- deca
+hecto- 100
+kilo- 1e3
+mega- 1e6
+giga- 1e9
+tera- 1e12
+peta- 1e15
+exa- 1e18
+zetta- 1e21
+yotta- 1e24
+
+deci- 1e-1
+centi- 1e-2
+milli- 1e-3
+micro- 1e-6
+nano- 1e-9
+pico- 1e-12
+femto- 1e-15
+atto- 1e-18
+zepto- 1e-21
+yocto- 1e-24
+
+da- deca
+D- deca
+h- hecto
+H- hecto
+k- kilo
+K- kilo
+M- mega
+G- giga
+T- tera
+P- peta
+E- exa
+Z- zetta
+Y- yotta
+
+d- deci
+c- centi
+m- milli
+u- micro
+n- nano
+p- pico
+f- femto
+a- atto
+z- zepto
+y- yocto
+
+# Binary prefixes (i.e. metric but 1024 replaces 1000)
+
+kibi- 1024^1
+mebi- 1024^2
+gibi- 1024^3
+tebi- 1024^4
+pebi- 1024^5
+exbi- 1024^6
+Ki- kibi
+Mi- mebi
+Gi- gibi
+Ti- tebi
+Pi- pebi
+Ei- exbi
+
+# Derived SI units
+# Note: it is best to have these before any non-SI units
+
+newton kg m / s^2
+N newton
+pascal N / m^2
+Pa pascal
+joule N m
+J joule
+watt J/s
+W watt
+coulomb A s
+C coulomb
+volt W/A
+V volt
+ohm V/A
+siemens A/V
+S siemens
+farad C/V
+F farad
+weber V s
+Wb weber
+henry V s / A
+H henry
+tesla Wb / m^2
+T tesla
+hertz 1 / s
+Hz hertz
+
+gram millikg
+g gram
+
+# Angle units and constants
+
+# Tau is the circle constant, equal to a circle's diameter divided by its radius
+tau 6.28318530717958
+# Another common circle constant
+pi tau / 2
+
+radian m / m
+rad radian
+steradian m^2 / m^2
+sr steradian
+degree tau / 360 radian
+deg degree
+° degree
+
+# Nonlinear units, which are not supported by the file reader and must be defined manually
+# Use tempC(100) for 100 degrees Celsius
+
+tempCelsius !
+tempFahrenheit !
+tempC tempCelsius
+tempF tempFahrenheit
+
+# Common time units
+minute 60 second
+min minute
+hour 3600 second
+h hour
+day 86400 second
+d day
+week 7 day
+wk week
+julianyear 365.25 day
+gregorianyear 365.2425 day
+gregorianmonth gregorianyear / 12
+
+# Other non-SI "metric" units
+litre 0.001 m^3
+liter litre
+l litre
+L litre
+tonne 1000 kg
+t tonne
+are 100 m^2
+hectare hectoare
+arcminute 1 / 60 degree
+arcmin arcminute
+arcsecond 1 / 60 arcminute
+arcsec arcsecond
+
+# constants
+waterdensity kilogram / litre
+
+# Imperial length units
+foot 0.3048 m
+ft foot
+inch foot / 12
+in inch
+yard 3 foot
+yd yard
+mile 1760 yard
+mi mile
+
+# Compressed notation
+kph km / hour
+mph mile / hour
+
+# Imperial weight units
+pound 0.45359237 kg
+lb pound
+ounce pound / 16
+oz ounce
+stone 14 lb
+UShundredweight 100 lb
+UKhundredweight 8 stone
+USimperialton 20 UShundredweight
+UKimperialton 10 UKhundredweight
+
+# Imperial volume units
+UKfluidounce ounce / waterdensity
+UKfloz UKfluidounce
+UKcup 10 UKfloz
+UKpint 2 UKcup
+UKquart 2 UKpint
+UKgallon 4 UKquart
+UKgal UKgallon
+
+USgallon 231 inch^3
+USgal USgallon
+USquart USgallon / 4
+USpint USquart / 2
+UScup USpint / 2
+USfluidounce UScup / 8
+USfloz USfluidounce
+UStablespoon USfluidounce / 2
+UStbsp UStablespoon
+USteaspoon UStablespoon / 3
+UStsp USteaspoon
+
+# Metric versions!
+# tsp = 5 mL, tbsp = 15 mL, floz = 30 mL, cup = 240 mL, pint = 480 mL, quart = 960 mL, gallon = 3840 mL
+# only metrictsp, metrictbsp and metriccup are common, the rest are derived from the US formulae with 240 mL cup
+metricteaspoon 5 mL
+teaspoon metricteaspoon
+tsp metricteaspoon
+metrictablespoon 3 metricteaspoon
+tablespoon metrictablespoon
+tbsp metrictablespoon
+metricfluidounce 2 metrictablespoon
+metriccup 8 metricfluidounce
+cup metriccup
+metricpint 2 metriccup
+pint metricpint
+metricquart 2 metricpint
+quart metricquart
+metricgallon 4 metricquart
+
+# Energy units
+calorie 4.18 J
+cal calorie
+Calorie kilocalorie
+Cal Calorie
+Wh W h
+
+# Extra units to only include in the dimension-based converter
+km km
+cm cm
+mm mm
+mg mg
+mL mL
+ml ml
+kJ kJ
+MJ MJ
+kWh kWh
+m/s m / s
+km/h km / h
+ft/s foot / s
+mi/h mile / hour \ No newline at end of file
diff --git a/src/org/unitConverter/math/ConditionalExistenceCollectionsTest.java b/src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java
index 311ace5..311ace5 100644
--- a/src/org/unitConverter/math/ConditionalExistenceCollectionsTest.java
+++ b/src/test/java/org/unitConverter/math/ConditionalExistenceCollectionsTest.java
diff --git a/src/org/unitConverter/math/ExpressionParserTest.java b/src/test/java/org/unitConverter/math/ExpressionParserTest.java
index f3180c1..f3180c1 100644
--- a/src/org/unitConverter/math/ExpressionParserTest.java
+++ b/src/test/java/org/unitConverter/math/ExpressionParserTest.java
diff --git a/src/org/unitConverter/math/ObjectProductTest.java b/src/test/java/org/unitConverter/math/ObjectProductTest.java
index afd18b7..afd18b7 100644
--- a/src/org/unitConverter/math/ObjectProductTest.java
+++ b/src/test/java/org/unitConverter/math/ObjectProductTest.java
diff --git a/src/org/unitConverter/unit/MultiUnitTest.java b/src/test/java/org/unitConverter/unit/MultiUnitTest.java
index 5ea9d07..5ea9d07 100644
--- a/src/org/unitConverter/unit/MultiUnitTest.java
+++ b/src/test/java/org/unitConverter/unit/MultiUnitTest.java
diff --git a/src/org/unitConverter/unit/UnitDatabaseTest.java b/src/test/java/org/unitConverter/unit/UnitDatabaseTest.java
index 2b981b6..f0ba8e5 100644
--- a/src/org/unitConverter/unit/UnitDatabaseTest.java
+++ b/src/test/java/org/unitConverter/unit/UnitDatabaseTest.java
@@ -70,8 +70,8 @@ class UnitDatabaseTest {
*
* @since 2019-05-03
*/
- @Test
- // @Timeout(value = 5, unit = TimeUnit.SECONDS)
+// @Test
+// @Timeout(value = 1, unit = TimeUnit.SECONDS)
public void testInfiniteSetExceptions() {
// load units
final UnitDatabase infiniteDatabase = new UnitDatabase();
diff --git a/src/org/unitConverter/unit/UnitTest.java b/src/test/java/org/unitConverter/unit/UnitTest.java
index c0711dc..3b594f2 100644
--- a/src/org/unitConverter/unit/UnitTest.java
+++ b/src/test/java/org/unitConverter/unit/UnitTest.java
@@ -16,8 +16,8 @@
*/
package org.unitConverter.unit;
-import static org.junit.Assert.assertFalse;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;