summaryrefslogtreecommitdiff
path: root/src/org/unitConverter/unit/UnitDatabase.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/unitConverter/unit/UnitDatabase.java')
-rw-r--r--src/org/unitConverter/unit/UnitDatabase.java88
1 files changed, 87 insertions, 1 deletions
diff --git a/src/org/unitConverter/unit/UnitDatabase.java b/src/org/unitConverter/unit/UnitDatabase.java
index c5432f7..56846a1 100644
--- a/src/org/unitConverter/unit/UnitDatabase.java
+++ b/src/org/unitConverter/unit/UnitDatabase.java
@@ -42,6 +42,7 @@ import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.unitConverter.math.ConditionalExistenceCollections;
import org.unitConverter.math.DecimalComparison;
import org.unitConverter.math.ExpressionParser;
import org.unitConverter.math.ObjectProduct;
@@ -1179,6 +1180,18 @@ public final class UnitDatabase {
private final Map<String, Unit> units;
/**
+ * The rule that specifies when prefix repetition is allowed. It takes in one
+ * argument: a list of the prefixes being applied to the unit
+ * <p>
+ * The prefixes are inputted in <em>application order</em>. This means that
+ * testing whether "kilomegagigametre" is a valid unit is equivalent to
+ * running the following code (assuming all variables are defined correctly):
+ * <br>
+ * {@code prefixRepetitionRule.test(Arrays.asList(giga, mega, kilo))}
+ */
+ private Predicate<List<UnitPrefix>> prefixRepetitionRule;
+
+ /**
* A parser that can parse unit expressions.
*
* @since 2019-03-22
@@ -1240,10 +1253,25 @@ public final class UnitDatabase {
* @since v0.1.0
*/
public UnitDatabase() {
+ this(prefixes -> true);
+ }
+
+ /**
+ * Creates the {@code UnitsDatabase}
+ *
+ * @param prefixRepetitionRule the rule that determines when prefix
+ * repetition is allowed
+ * @since 2020-08-26
+ */
+ public UnitDatabase(Predicate<List<UnitPrefix>> prefixRepetitionRule) {
this.prefixlessUnits = new HashMap<>();
this.prefixes = new HashMap<>();
this.dimensions = new HashMap<>();
- this.units = new PrefixedUnitMap(this.prefixlessUnits, this.prefixes);
+ this.prefixRepetitionRule = prefixRepetitionRule;
+ this.units = ConditionalExistenceCollections.conditionalExistenceMap(
+ new PrefixedUnitMap(this.prefixlessUnits, this.prefixes),
+ entry -> this.prefixRepetitionRule
+ .test(this.getPrefixesFromName(entry.getKey())));
}
/**
@@ -1645,6 +1673,47 @@ public final class UnitDatabase {
}
/**
+ * Gets all of the prefixes that are on a unit name, in application order.
+ *
+ * @param unitName name of unit
+ * @return prefixes
+ * @since 2020-08-26
+ */
+ List<UnitPrefix> getPrefixesFromName(final String unitName) {
+ if (this.prefixlessUnits.containsKey(unitName))
+ return new ArrayList<>();
+ else {
+ // find the longest prefix
+ String longestPrefix = null;
+ int longestLength = 0;
+
+ for (final String prefixName : this.prefixes.keySet()) {
+ // a prefix name is valid if:
+ // - it is prefixed (i.e. the unit name starts with it)
+ // - it is longer than the existing largest prefix (since I am
+ // looking for the longest valid prefix)
+ // - the part after the prefix is a valid unit name
+ // - the unit described that name is a linear unit (since only
+ // linear units can have prefixes)
+ if (unitName.startsWith(prefixName)
+ && prefixName.length() > longestLength) {
+ final String rest = unitName.substring(prefixName.length());
+ if (this.containsUnitName(rest)
+ && this.getUnit(rest) instanceof LinearUnit) {
+ longestPrefix = prefixName;
+ longestLength = prefixName.length();
+ }
+ }
+ }
+
+ final List<UnitPrefix> prefixes = this
+ .getPrefixesFromName(unitName.substring(longestLength));
+ prefixes.add(this.getPrefix(longestPrefix));
+ return prefixes;
+ }
+ }
+
+ /**
* Gets a unit prefix from a prefix expression
* <p>
* Currently, prefix expressions are much simpler than unit expressions: They
@@ -1679,6 +1748,14 @@ public final class UnitDatabase {
}
/**
+ * @return the prefixRepetitionRule
+ * @since 2020-08-26
+ */
+ public final Predicate<List<UnitPrefix>> getPrefixRepetitionRule() {
+ return this.prefixRepetitionRule;
+ }
+
+ /**
* Gets a unit from the database from its name, looking for prefixes.
*
* @param name unit's name
@@ -1863,6 +1940,15 @@ public final class UnitDatabase {
}
/**
+ * @param prefixRepetitionRule the prefixRepetitionRule to set
+ * @since 2020-08-26
+ */
+ public final void setPrefixRepetitionRule(
+ Predicate<List<UnitPrefix>> prefixRepetitionRule) {
+ this.prefixRepetitionRule = prefixRepetitionRule;
+ }
+
+ /**
* @return a string stating the number of units, prefixes and dimensions in
* the database
*/