diff options
author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2019-04-13 19:48:25 -0400 |
---|---|---|
committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2019-04-13 19:48:25 -0400 |
commit | 63dd50e5d7a5daa0bcbdd00608543d4572c870ea (patch) | |
tree | f35c4619e05ddb3dd33b614dccefd9839dc35512 | |
parent | f0f4898f796b9cc26294ba9feb22692143d00a9e (diff) |
Edited the UnitsDatabase API; it now favours prefixless units.
-rw-r--r-- | CHANGELOG.org | 2 | ||||
-rwxr-xr-x | src/org/unitConverter/UnitsDatabase.java | 753 | ||||
-rwxr-xr-x | src/org/unitConverter/converterGUI/UnitConverterGUI.java | 18 | ||||
-rw-r--r-- | src/org/unitConverter/math/ExpressionParser.java | 2 |
4 files changed, 689 insertions, 86 deletions
diff --git a/CHANGELOG.org b/CHANGELOG.org index e7748ba..db9766b 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -3,6 +3,8 @@ All notable changes in this project will be shown in this file. ** Unreleased *** Changed + - When searching for units, units with no prefixes are searched for before prefixed units + - Smaller prefixes are searched for before larger prefixes - Moved project to Maven - Downgraded JUnit to 4.11 - BaseUnit is now a subclass of LinearUnit diff --git a/src/org/unitConverter/UnitsDatabase.java b/src/org/unitConverter/UnitsDatabase.java index a7e6047..9749e9c 100755 --- a/src/org/unitConverter/UnitsDatabase.java +++ b/src/org/unitConverter/UnitsDatabase.java @@ -21,14 +21,20 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.util.AbstractSet; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; import org.unitConverter.dimension.UnitDimension; import org.unitConverter.math.DecimalComparison; @@ -40,7 +46,7 @@ import org.unitConverter.unit.Unit; import org.unitConverter.unit.UnitPrefix; /** - * A database of units and prefixes, and their names. + * A database of units, prefixes and dimensions, and their names. * * @author Adrien Hopkins * @since 2019-01-07 @@ -48,6 +54,645 @@ import org.unitConverter.unit.UnitPrefix; */ public final class UnitsDatabase { /** + * A map for units that allows the use of prefixes. + * <p> + * As this map implementation is intended to be used as a sort of "augmented view" of a unit and prefix map, it is + * unmodifiable but instead reflects the changes to the maps passed into it. Do not edit this map, instead edit the + * maps that were passed in during construction. + * </p> + * <p> + * The rules for applying prefixes onto units are the following: + * <ul> + * <li>Prefixes can only be applied to linear units.</li> + * <li>Before attempting to search for prefixes in a unit name, this map will first search for a unit name. So, if + * there are two units, "B" and "AB", and a prefix "A", this map will favour the unit "AB" over the unit "B" with + * the prefix "A", even though they have the same string.</li> + * <li>Shorter prefixes are preferred to longer prefixes. So, if you have units "BC" and "C", and prefixes "AB" and + * "A", inputting "ABC" will return the unit "BC" with the prefix "A", not "C" with the prefix "AB".</li> + * </ul> + * </p> + * + * @author Adrien Hopkins + * @since 2019-04-13 + */ + private static final class PrefixedUnitMap implements Map<String, Unit> { + /** + * The class used for entry sets. + * + * @author Adrien Hopkins + * @since 2019-04-13 + */ + private static final class PrefixedUnitEntrySet extends AbstractSet<Map.Entry<String, Unit>> { + // the map that created this set + private final PrefixedUnitMap map; + + /** + * Creates the {@code PrefixedUnitNameSet}. + * + * @param map + * @since 2019-04-13 + */ + public PrefixedUnitEntrySet(final PrefixedUnitMap map) { + this.map = map; + } + + @Override + public boolean add(final Map.Entry<String, Unit> e) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection<? extends Map.Entry<String, Unit>> c) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean contains(final Object o) { + // get the entry + final Entry<String, Unit> entry; + + try { + // This is OK because I'm in a try-catch block. + @SuppressWarnings("unchecked") + final Entry<String, Unit> tempEntry = (Entry<String, Unit>) o; + entry = tempEntry; + } catch (final ClassCastException e) { + throw new IllegalArgumentException("Attempted to test for an entry using a non-entry."); + } + + return this.map.containsKey(entry.getKey()) && this.map.get(entry.getKey()).equals(entry.getValue()); + } + + @Override + public boolean containsAll(final Collection<?> c) { + for (final Object o : c) + if (!this.contains(o)) + return false; + return true; + } + + @Override + public boolean isEmpty() { + return this.map.isEmpty(); + } + + @Override + public Iterator<Entry<String, Unit>> iterator() { + return new Iterator<Entry<String, Unit>>() { + // position in the unit list + int unitNamePosition = -1; + // the indices of the prefixes attached to the current unit + List<Integer> prefixCoordinates = new ArrayList<>(); + + List<String> unitNames = new ArrayList<>(PrefixedUnitEntrySet.this.map.units.keySet()); + List<String> prefixNames = new ArrayList<>(PrefixedUnitEntrySet.this.map.prefixes.keySet()); + + @Override + public boolean hasNext() { + if (this.unitNames.isEmpty()) + return false; + else { + if (this.prefixNames.isEmpty()) + return this.unitNamePosition >= this.unitNames.size() - 1; + else + return true; + } + } + + @Override + public Entry<String, Unit> next() { + // increment unit name position + this.unitNamePosition++; + + // if I have prefixes, ensure I'm not using a nonlinear unit + // since all of the unprefixed stuff is done, just remove nonlinear units + if (!this.prefixCoordinates.isEmpty()) { + while (!(PrefixedUnitEntrySet.this.map + .get(this.unitNames.get(this.unitNamePosition)) instanceof LinearUnit)) { + this.unitNames.remove(this.unitNamePosition); + } + } + + // carry over + if (!this.prefixNames.isEmpty() && this.unitNamePosition >= this.unitNames.size() - 1) { + // handle prefix position + this.unitNamePosition = 0; + int i = this.prefixCoordinates.size() - 1; + this.prefixCoordinates.set(i, this.prefixCoordinates.get(i) + 1); + + while (this.prefixCoordinates.get(i) >= this.prefixNames.size() - 1) { + this.prefixCoordinates.set(i, 0); + i--; + if (i < 0) { + this.prefixCoordinates.add(0, 0); + } + } + } + + final StringBuilder unitNameBuilder = new StringBuilder(); + for (final int i : this.prefixCoordinates) { + unitNameBuilder.append(this.prefixNames.get(i)); + } + unitNameBuilder.append(this.unitNames.get(this.unitNamePosition)); + + final String unitName = unitNameBuilder.toString(); + return new Entry<String, Unit>() { + @Override + public String getKey() { + return unitName; + } + + @Override + public Unit getValue() { + return PrefixedUnitEntrySet.this.map.get(unitName); + } + + @Override + public Unit setValue(final Unit value) { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + @Override + public boolean remove(final Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeIf(final Predicate<? super Entry<String, Unit>> filter) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + if (this.map.units.isEmpty()) + return 0; + else { + if (this.map.prefixes.isEmpty()) + return this.map.units.size(); + else + // infinite set + return Integer.MAX_VALUE; + } + } + + @Override + public Object[] toArray() { + if (this.map.units.isEmpty()) + // finite, it will work + return super.toArray(); + else { + if (this.map.prefixes.isEmpty()) + // finite, it will work + return super.toArray(); + else + // infinite set + throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + } + } + + @Override + public <T> T[] toArray(final T[] a) { + if (this.map.units.isEmpty()) + // finite, it will work + return super.toArray(a); + else { + if (this.map.prefixes.isEmpty()) + // finite, it will work + return super.toArray(a); + else + // infinite set + throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + } + } + + } + + /** + * The class used for unit name sets. + * + * @author Adrien Hopkins + * @since 2019-04-13 + */ + private static final class PrefixedUnitNameSet extends AbstractSet<String> { + // the map that created this set + private final PrefixedUnitMap map; + + /** + * Creates the {@code PrefixedUnitNameSet}. + * + * @param map + * @since 2019-04-13 + */ + public PrefixedUnitNameSet(final PrefixedUnitMap map) { + this.map = map; + } + + @Override + public boolean add(final String e) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(final Collection<? extends String> c) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean contains(final Object o) { + return this.map.containsKey(o); + } + + @Override + public boolean containsAll(final Collection<?> c) { + for (final Object o : c) + if (!this.contains(o)) + return false; + return true; + } + + @Override + public boolean isEmpty() { + return this.map.isEmpty(); + } + + @Override + public Iterator<String> iterator() { + return new Iterator<String>() { + // position in the unit list + int unitNamePosition = -1; + // the indices of the prefixes attached to the current unit + List<Integer> prefixCoordinates = new ArrayList<>(); + + List<String> unitNames = new ArrayList<>(PrefixedUnitNameSet.this.map.units.keySet()); + List<String> prefixNames = new ArrayList<>(PrefixedUnitNameSet.this.map.prefixes.keySet()); + + @Override + public boolean hasNext() { + if (this.unitNames.isEmpty()) + return false; + else { + if (this.prefixNames.isEmpty()) + return this.unitNamePosition >= this.unitNames.size() - 1; + else + return true; + } + } + + @Override + public String next() { + // increment unit name position + this.unitNamePosition++; + + // if I have prefixes, ensure I'm not using a nonlinear unit + // since all of the unprefixed stuff is done, just remove nonlinear units + if (!this.prefixCoordinates.isEmpty()) { + while (!(PrefixedUnitNameSet.this.map + .get(this.unitNames.get(this.unitNamePosition)) instanceof LinearUnit)) { + this.unitNames.remove(this.unitNamePosition); + } + } + + // carry over + if (!this.prefixNames.isEmpty() && this.unitNamePosition >= this.unitNames.size() - 1) { + // handle prefix position + this.unitNamePosition = 0; + int i = this.prefixCoordinates.size() - 1; + this.prefixCoordinates.set(i, this.prefixCoordinates.get(i) + 1); + + while (this.prefixCoordinates.get(i) >= this.prefixNames.size() - 1) { + this.prefixCoordinates.set(i, 0); + i--; + if (i < 0) { + this.prefixCoordinates.add(0, 0); + } + } + } + + final StringBuilder unitName = new StringBuilder(); + for (final int i : this.prefixCoordinates) { + unitName.append(this.prefixNames.get(i)); + } + unitName.append(this.unitNames.get(this.unitNamePosition)); + return unitName.toString(); + } + }; + } + + @Override + public boolean remove(final Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(final Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeIf(final Predicate<? super String> filter) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(final Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + if (this.map.units.isEmpty()) + return 0; + else { + if (this.map.prefixes.isEmpty()) + return this.map.units.size(); + else + // infinite set + return Integer.MAX_VALUE; + } + } + + @Override + public Object[] toArray() { + if (this.map.units.isEmpty()) + // finite, it will work + return super.toArray(); + else { + if (this.map.prefixes.isEmpty()) + // finite, it will work + return super.toArray(); + else + // infinite set + throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + } + } + + @Override + public <T> T[] toArray(final T[] a) { + if (this.map.units.isEmpty()) + // finite, it will work + return super.toArray(a); + else { + if (this.map.prefixes.isEmpty()) + // finite, it will work + return super.toArray(a); + else + // infinite set + throw new UnsupportedOperationException("Cannot make an infinite set into an array."); + } + } + + } + + /** + * The units stored in this collection, without prefixes. + * + * @since 2019-04-13 + */ + private final Map<String, Unit> units; + + /** + * The available prefixes for use. + * + * @since 2019-04-13 + */ + private final Map<String, UnitPrefix> prefixes; + + // caches + private Collection<Unit> values = null; + private Set<String> keySet = null; + private Set<Entry<String, Unit>> entrySet = null; + + /** + * Creates the {@code PrefixedUnitMap}. + * + * @param units + * @param prefixes + * @since 2019-04-13 + */ + public PrefixedUnitMap(final Map<String, Unit> units, final Map<String, UnitPrefix> prefixes) { + // I am making unmodifiable maps to ensure I don't accidentally make changes. + this.units = Collections.unmodifiableMap(units); + this.prefixes = Collections.unmodifiableMap(prefixes); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Unit compute(final String key, + final BiFunction<? super String, ? super Unit, ? extends Unit> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public Unit computeIfAbsent(final String key, final Function<? super String, ? extends Unit> mappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public Unit computeIfPresent(final String key, + final BiFunction<? super String, ? super Unit, ? extends Unit> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsKey(final Object key) { + // First, test if there is a unit with the key + if (this.units.containsKey(key)) + return true; + + // Next, try to cast it to String + if (!(key instanceof String)) + throw new IllegalArgumentException("Attempted to test for a unit using a non-string name."); + final String unitName = (String) key; + + // Then, look for the shortest prefix that is attached to a valid unit + String shortestPrefix = null; + int shortestLength = Integer.MAX_VALUE; + + 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 shorter than the existing largest prefix (since I am looking for the smallest 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() < shortestLength) { + final String rest = unitName.substring(prefixName.length()); + if (this.containsKey(rest) && this.get(rest) instanceof LinearUnit) { + shortestPrefix = prefixName; + shortestLength = prefixName.length(); + } + } + } + + return shortestPrefix != null; + } + + @Override + public boolean containsValue(final Object value) { + return this.units.containsValue(value); + } + + @Override + public Set<Entry<String, Unit>> entrySet() { + if (this.entrySet == null) { + this.entrySet = new PrefixedUnitEntrySet(this); + } + return this.entrySet; + } + + @Override + public Unit get(final Object key) { + // First, test if there is a unit with the key + if (this.units.containsKey(key)) + return this.units.get(key); + + // Next, try to cast it to String + if (!(key instanceof String)) + throw new IllegalArgumentException("Attempted to obtain a unit using a non-string name."); + final String unitName = (String) key; + + // Then, look for the shortest prefix that is attached to a valid unit + String shortestPrefix = null; + int shortestLength = Integer.MAX_VALUE; + + 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 shorter than the existing largest prefix (since I am looking for the smallest 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() < shortestLength) { + final String rest = unitName.substring(prefixName.length()); + if (this.containsKey(rest) && this.get(rest) instanceof LinearUnit) { + shortestPrefix = prefixName; + shortestLength = prefixName.length(); + } + } + } + + // if none found, returns null + if (shortestPrefix == null) + return null; + else { + // get necessary data + final String rest = unitName.substring(shortestLength); + // this cast will not fail because I verified that it would work before selecting this prefix + final LinearUnit unit = (LinearUnit) this.get(rest); + final UnitPrefix prefix = this.prefixes.get(shortestPrefix); + + return unit.withPrefix(prefix); + } + } + + @Override + public boolean isEmpty() { + return this.units.isEmpty(); + } + + @Override + public Set<String> keySet() { + if (this.keySet == null) { + this.keySet = new PrefixedUnitNameSet(this); + } + return this.keySet; + } + + @Override + public Unit merge(final String key, final Unit value, + final BiFunction<? super Unit, ? super Unit, ? extends Unit> remappingFunction) { + throw new UnsupportedOperationException(); + } + + @Override + public Unit put(final String key, final Unit value) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(final Map<? extends String, ? extends Unit> m) { + throw new UnsupportedOperationException(); + } + + @Override + public Unit putIfAbsent(final String key, final Unit value) { + throw new UnsupportedOperationException(); + } + + @Override + public Unit remove(final Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(final Object key, final Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Unit replace(final String key, final Unit value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean replace(final String key, final Unit oldValue, final Unit newValue) { + throw new UnsupportedOperationException(); + } + + @Override + public void replaceAll(final BiFunction<? super String, ? super Unit, ? extends Unit> function) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + if (this.units.isEmpty()) + return 0; + else { + if (this.prefixes.isEmpty()) + return this.units.size(); + else + // infinite set + return Integer.MAX_VALUE; + } + } + + @Override + public Collection<Unit> values() { + if (this.values == null) { + this.values = Collections.unmodifiableCollection(this.units.values()); + } + return this.values; + } + } + + /** * The exponent operator * * @param base @@ -57,7 +702,7 @@ public final class UnitsDatabase { * @return result * @since 2019-04-10 */ - private static final LinearUnit exponent(final LinearUnit base, final LinearUnit exponentUnit) { + private static final LinearUnit exponentiateUnits(final LinearUnit base, final LinearUnit exponentUnit) { // exponent function - first check if o2 is a number, if (exponentUnit.getBase().equals(SI.SI.getBaseUnit(UnitDimension.EMPTY))) { // then check if it is an integer, @@ -74,12 +719,12 @@ public final class UnitsDatabase { } /** - * The units in this system. + * The units in this system, excluding prefixes. * * @since 2019-01-07 * @since v0.1.0 */ - private final Map<String, Unit> units; + private final Map<String, Unit> prefixlessUnits; /** * The unit prefixes in this system. @@ -97,6 +742,13 @@ public final class UnitsDatabase { private final Map<String, UnitDimension> dimensions; /** + * A map mapping strings to units (including prefixes) + * + * @since 2019-04-13 + */ + private final Map<String, Unit> units; + + /** * A parser that can parse unit expressions. * * @since 2019-03-22 @@ -106,7 +758,7 @@ public final class UnitsDatabase { .addBinaryOperator("-", (o1, o2) -> o1.minus(o2), 0) .addBinaryOperator("*", (o1, o2) -> o1.times(o2), 1).addSpaceFunction("*") .addBinaryOperator("/", (o1, o2) -> o1.dividedBy(o2), 1) - .addBinaryOperator("^", UnitsDatabase::exponent, 2).build(); + .addBinaryOperator("^", UnitsDatabase::exponentiateUnits, 2).build(); /** * A parser that can parse unit prefix expressions @@ -134,9 +786,10 @@ public final class UnitsDatabase { * @since v0.1.0 */ public UnitsDatabase() { - this.units = new HashMap<>(); + this.prefixlessUnits = new HashMap<>(); this.prefixes = new HashMap<>(); this.dimensions = new HashMap<>(); + this.units = new PrefixedUnitMap(this.prefixlessUnits, this.prefixes); } /** @@ -236,7 +889,7 @@ public final class UnitsDatabase { * @since v0.1.0 */ public void addUnit(final String name, final Unit unit) { - this.units.put(Objects.requireNonNull(name, "name must not be null."), + this.prefixlessUnits.put(Objects.requireNonNull(name, "name must not be null."), Objects.requireNonNull(unit, "unit must not be null.")); } @@ -314,19 +967,6 @@ public final class UnitsDatabase { } /** - * Tests if the database has a unit with this name, ignoring prefixes - * - * @param name - * name to test - * @return if database contains name - * @since 2019-01-13 - * @since v0.1.0 - */ - public boolean containsPrefixlessUnitName(final String name) { - return this.units.containsKey(name); - } - - /** * Tests if the database has a unit prefix with this name. * * @param name @@ -349,21 +989,15 @@ public final class UnitsDatabase { * @since v0.1.0 */ public boolean containsUnitName(final String name) { - // check for prefixes - for (final String prefixName : this.prefixNameSet()) { - if (name.startsWith(prefixName)) - if (this.containsUnitName(name.substring(prefixName.length()))) - return true; - } return this.units.containsKey(name); } /** - * @return an immutable set of all of the dimension names in this database. - * @since 2019-03-14 + * @return a map mapping dimension names to dimensions + * @since 2019-04-13 */ - public Set<String> dimensionNameSet() { - return Collections.unmodifiableSet(this.dimensions.keySet()); + public Map<String, UnitDimension> dimensionMap() { + return Collections.unmodifiableMap(this.dimensions); } /** @@ -520,19 +1154,6 @@ public final class UnitsDatabase { } /** - * Gets a unit from the database from its name, ignoring prefixes. - * - * @param name - * unit's name - * @return unit - * @since 2019-01-10 - * @since v0.1.0 - */ - public Unit getPrefixlessUnit(final String name) { - return this.units.get(name); - } - - /** * Gets a unit from the database from its name, looking for prefixes. * * @param name @@ -546,24 +1167,6 @@ public final class UnitsDatabase { final double value = Double.parseDouble(name); return SI.SI.getBaseUnit(UnitDimension.EMPTY).times(value); } catch (final NumberFormatException e) { - for (final String prefixName : this.prefixNameSet()) { - // check for a prefix - if (name.startsWith(prefixName)) { - // prefix found! Make sure what comes after it is actually a unit! - final String prefixless = name.substring(prefixName.length()); - if (this.containsUnitName(prefixless)) { - // yep, it's a proper prefix! Get the unit! - final Unit unit = this.getUnit(prefixless); - final UnitPrefix prefix = this.getPrefix(prefixName); - - // Prefixes only work with linear and base units, so make sure it's one of those - if (unit instanceof LinearUnit) { - final LinearUnit linearUnit = (LinearUnit) unit; - return linearUnit.withPrefix(prefix); - } - } - } - } return this.units.get(name); } @@ -703,28 +1306,26 @@ public final class UnitsDatabase { } /** - * @return an immutable set of all of the unit names in this database, ignoring prefixes - * @since 2019-01-14 - * @since v0.1.0 + * @return a map mapping prefix names to prefixes + * @since 2019-04-13 */ - public Set<String> prefixlessUnitNameSet() { - return Collections.unmodifiableSet(this.units.keySet()); + public Map<String, UnitPrefix> prefixMap() { + return Collections.unmodifiableMap(this.prefixes); } /** - * @return an immutable set of all of the units in this database, ignoring prefixes. - * @since 2019-04-10 + * @return a map mapping unit names to units, including prefixed names + * @since 2019-04-13 */ - public Set<Unit> prefixlessUnitSet() { - return Collections.unmodifiableSet(new HashSet<>(this.units.values())); + public Map<String, Unit> unitMap() { + return this.units; // PrefixedUnitMap is immutable so I don't need to make an unmodifiable map. } /** - * @return an immutable set of all of the prefix names in this database - * @since 2019-01-14 - * @since v0.1.0 + * @return a map mapping unit names to units, ignoring prefixes + * @since 2019-04-13 */ - public Set<String> prefixNameSet() { - return Collections.unmodifiableSet(this.prefixes.keySet()); + public Map<String, Unit> unitMapPrefixless() { + return Collections.unmodifiableMap(this.prefixlessUnits); } } diff --git a/src/org/unitConverter/converterGUI/UnitConverterGUI.java b/src/org/unitConverter/converterGUI/UnitConverterGUI.java index 9314510..49a40d6 100755 --- a/src/org/unitConverter/converterGUI/UnitConverterGUI.java +++ b/src/org/unitConverter/converterGUI/UnitConverterGUI.java @@ -24,6 +24,7 @@ import java.math.MathContext; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; @@ -143,19 +144,19 @@ final class UnitConverterGUI { return o1.compareTo(o2); }; - this.unitNames = new ArrayList<>(this.units.prefixlessUnitNameSet()); + this.unitNames = new ArrayList<>(this.units.unitMapPrefixless().keySet()); this.unitNames.sort(null); // sorts it using Comparable - this.unitNamesFiltered = new DelegateListModel<>(new ArrayList<>(this.units.prefixlessUnitNameSet())); + this.unitNamesFiltered = new DelegateListModel<>(new ArrayList<>(this.units.unitMapPrefixless().keySet())); this.unitNamesFiltered.sort(null); // sorts it using Comparable - this.prefixNames = new ArrayList<>(this.units.prefixNameSet()); + this.prefixNames = new ArrayList<>(this.units.prefixMap().keySet()); this.prefixNames.sort(this.prefixNameComparator); // sorts it using my comparator - this.prefixNamesFiltered = new DelegateListModel<>(new ArrayList<>(this.units.prefixNameSet())); + this.prefixNamesFiltered = new DelegateListModel<>(new ArrayList<>(this.units.prefixMap().keySet())); this.prefixNamesFiltered.sort(this.prefixNameComparator); // sorts it using my comparator - this.dimensionNames = new DelegateListModel<>(new ArrayList<>(this.units.dimensionNameSet())); + this.dimensionNames = new DelegateListModel<>(new ArrayList<>(this.units.dimensionMap().keySet())); this.dimensionNames.sort(null); // sorts it using Comparable // a Predicate that returns true iff the argument is a full base unit @@ -163,8 +164,9 @@ final class UnitConverterGUI { // print out unit counts System.out.printf("Successfully loaded %d units with %d unit names (%d base units).%n", - this.units.prefixlessUnitSet().size(), this.units.prefixlessUnitNameSet().size(), - this.units.prefixlessUnitSet().stream().filter(isFullBase).count()); + new HashSet<>(this.units.unitMapPrefixless().values()).size(), + this.units.unitMapPrefixless().size(), + new HashSet<>(this.units.unitMapPrefixless().values()).stream().filter(isFullBase).count()); } /** @@ -449,7 +451,7 @@ final class UnitConverterGUI { } public final Set<String> unitNameSet() { - return this.units.prefixlessUnitNameSet(); + return this.units.unitMapPrefixless().keySet(); } } diff --git a/src/org/unitConverter/math/ExpressionParser.java b/src/org/unitConverter/math/ExpressionParser.java index b56fa71..d01afaa 100644 --- a/src/org/unitConverter/math/ExpressionParser.java +++ b/src/org/unitConverter/math/ExpressionParser.java @@ -510,8 +510,6 @@ public final class ExpressionParser<T> { expressionRPN = expressionRPN.substring(0, expressionRPN.length() - 1); } return expressionRPN; - - // TODO document org.unitConverter.expressionParser.ExpressionParser.convertExpressionToPolish(expression) } /** |