summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnits/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/sevenUnits/utils')
-rw-r--r--src/main/java/sevenUnits/utils/NameSymbol.java299
-rw-r--r--src/main/java/sevenUnits/utils/Nameable.java59
-rw-r--r--src/main/java/sevenUnits/utils/NamedObjectProduct.java7
-rw-r--r--src/main/java/sevenUnits/utils/ObjectProduct.java6
4 files changed, 365 insertions, 6 deletions
diff --git a/src/main/java/sevenUnits/utils/NameSymbol.java b/src/main/java/sevenUnits/utils/NameSymbol.java
new file mode 100644
index 0000000..aea274b
--- /dev/null
+++ b/src/main/java/sevenUnits/utils/NameSymbol.java
@@ -0,0 +1,299 @@
+/**
+ * Copyright (C) 2019 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 sevenUnits.utils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * A class that can be used to specify names and a symbol for a unit.
+ *
+ * @author Adrien Hopkins
+ * @since 2019-10-21
+ */
+public final class NameSymbol {
+ public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(),
+ Optional.empty(), new HashSet<>());
+
+ /**
+ * Creates a {@code NameSymbol}, ensuring that if primaryName is null and
+ * otherNames is not empty, one name is moved from otherNames to primaryName
+ *
+ * Ensure that otherNames is a copy of the inputted argument.
+ */
+ private static final NameSymbol create(final String name,
+ final String symbol, final Set<String> otherNames) {
+ final Optional<String> primaryName;
+
+ if (name == null && !otherNames.isEmpty()) {
+ // get primary name and remove it from savedNames
+ final Iterator<String> it = otherNames.iterator();
+ assert it.hasNext();
+ primaryName = Optional.of(it.next());
+ otherNames.remove(primaryName.get());
+ } else {
+ primaryName = Optional.ofNullable(name);
+ }
+
+ return new NameSymbol(primaryName, Optional.ofNullable(symbol),
+ otherNames);
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and no other
+ * names.
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if name or symbol is null
+ */
+ public static final NameSymbol of(final String name, final String symbol) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>());
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol,
+ final Set<String> otherNames) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>(Objects.requireNonNull(otherNames,
+ "otherNames must not be null.")));
+ }
+
+ /**
+ * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if any argument is null
+ */
+ public static final NameSymbol of(final String name, final String symbol,
+ final String... otherNames) {
+ return new NameSymbol(Optional.of(name), Optional.of(symbol),
+ new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames,
+ "otherNames must not be null."))));
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, no symbol, and no other
+ * names.
+ *
+ * @param name name to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if name is null
+ */
+ public static final NameSymbol ofName(final String name) {
+ return new NameSymbol(Optional.of(name), Optional.empty(),
+ new HashSet<>());
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ * <p>
+ * If any argument is null, this static factory replaces it with an empty
+ * Optional or empty Set.
+ * <p>
+ * If {@code name} is null and {@code otherNames} is not empty, a primary
+ * name will be picked from {@code otherNames}. This name will not appear in
+ * getOtherNames().
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-11-26
+ */
+ public static final NameSymbol ofNullable(final String name,
+ final String symbol, final Set<String> otherNames) {
+ return NameSymbol.create(name, symbol,
+ otherNames == null ? new HashSet<>() : new HashSet<>(otherNames));
+ }
+
+ /**
+ * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional
+ * names.
+ * <p>
+ * If any argument is null, this static factory replaces it with an empty
+ * Optional or empty Set.
+ * <p>
+ * If {@code name} is null and {@code otherNames} is not empty, a primary
+ * name will be picked from {@code otherNames}. This name will not appear in
+ * getOtherNames().
+ *
+ * @param name name to use
+ * @param symbol symbol to use
+ * @param otherNames other names to use
+ * @return NameSymbol instance
+ * @since 2019-11-26
+ */
+ public static final NameSymbol ofNullable(final String name,
+ final String symbol, final String... otherNames) {
+ return create(name, symbol, otherNames == null ? new HashSet<>()
+ : new HashSet<>(Arrays.asList(otherNames)));
+ }
+
+ /**
+ * Gets a {@code NameSymbol} with a symbol and no names.
+ *
+ * @param symbol symbol to use
+ * @return NameSymbol instance
+ * @since 2019-10-21
+ * @throws NullPointerException if symbol is null
+ */
+ public static final NameSymbol ofSymbol(final String symbol) {
+ return new NameSymbol(Optional.empty(), Optional.of(symbol),
+ new HashSet<>());
+ }
+
+ private final Optional<String> primaryName;
+ private final Optional<String> symbol;
+
+ private final Set<String> otherNames;
+
+ /**
+ * Creates the {@code NameSymbol}.
+ *
+ * @param primaryName primary name of unit
+ * @param symbol symbol used to represent unit
+ * @param otherNames other names and/or spellings, should be a mutable copy
+ * of the argument
+ * @since 2019-10-21
+ */
+ private NameSymbol(final Optional<String> primaryName,
+ final Optional<String> symbol, final Set<String> otherNames) {
+ this.primaryName = primaryName;
+ this.symbol = symbol;
+ otherNames.remove(null);
+ this.otherNames = Collections.unmodifiableSet(otherNames);
+
+ if (this.primaryName.isEmpty()) {
+ assert this.otherNames.isEmpty();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof NameSymbol))
+ return false;
+ final NameSymbol other = (NameSymbol) obj;
+ if (this.otherNames == null) {
+ if (other.otherNames != null)
+ return false;
+ } else if (!this.otherNames.equals(other.otherNames))
+ return false;
+ if (this.primaryName == null) {
+ if (other.primaryName != null)
+ return false;
+ } else if (!this.primaryName.equals(other.primaryName))
+ return false;
+ if (this.symbol == null) {
+ if (other.symbol != null)
+ return false;
+ } else if (!this.symbol.equals(other.symbol))
+ return false;
+ return true;
+ }
+
+ /**
+ * @return otherNames
+ * @since 2019-10-21
+ */
+ public final Set<String> getOtherNames() {
+ return this.otherNames;
+ }
+
+ /**
+ * @return primaryName
+ * @since 2019-10-21
+ */
+ public final Optional<String> getPrimaryName() {
+ return this.primaryName;
+ }
+
+ /**
+ * @return symbol
+ * @since 2019-10-21
+ */
+ public final Optional<String> getSymbol() {
+ return this.symbol;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + (this.otherNames == null ? 0 : this.otherNames.hashCode());
+ result = prime * result
+ + (this.primaryName == null ? 0 : this.primaryName.hashCode());
+ result = prime * result
+ + (this.symbol == null ? 0 : this.symbol.hashCode());
+ return result;
+ }
+
+ /**
+ * @return true iff this {@code NameSymbol} contains no names or symbols.
+ */
+ public final boolean isEmpty() {
+ // if primaryName is empty, otherNames must also be empty
+ return this.primaryName.isEmpty() && this.symbol.isEmpty();
+ }
+
+ /**
+ * @return a short version of this NameSymbol (defaults to symbol instead of
+ * primary name)
+ * @since 2022-02-26
+ */
+ public String shortName() {
+ return this.symbol.or(this::getPrimaryName).orElse("EMPTY");
+ }
+
+ @Override
+ public String toString() {
+ if (this.isEmpty())
+ return "NameSymbol.EMPTY";
+ else if (this.primaryName.isPresent() && this.symbol.isPresent())
+ return this.primaryName + " (" + this.symbol + ")";
+ else
+ return this.primaryName.orElseGet(this.symbol::orElseThrow);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/sevenUnits/utils/Nameable.java b/src/main/java/sevenUnits/utils/Nameable.java
new file mode 100644
index 0000000..3cfc05a
--- /dev/null
+++ b/src/main/java/sevenUnits/utils/Nameable.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2020 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 sevenUnits.utils;
+
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * An object that can hold one or more names, and possibly a symbol. The name
+ * and symbol data should be immutable.
+ *
+ * @since 2020-09-07
+ */
+public interface Nameable {
+ /**
+ * @return a {@code NameSymbol} that contains this object's primary name,
+ * symbol and other names
+ * @since 2020-09-07
+ */
+ NameSymbol getNameSymbol();
+
+ /**
+ * @return set of alternate names
+ * @since 2020-09-07
+ */
+ default Set<String> getOtherNames() {
+ return this.getNameSymbol().getOtherNames();
+ }
+
+ /**
+ * @return preferred name of object
+ * @since 2020-09-07
+ */
+ default Optional<String> getPrimaryName() {
+ return this.getNameSymbol().getPrimaryName();
+ }
+
+ /**
+ * @return short symbol representing object
+ * @since 2020-09-07
+ */
+ default Optional<String> getSymbol() {
+ return this.getNameSymbol().getSymbol();
+ }
+}
diff --git a/src/main/java/sevenUnits/utils/NamedObjectProduct.java b/src/main/java/sevenUnits/utils/NamedObjectProduct.java
index 514f0b1..9c3079c 100644
--- a/src/main/java/sevenUnits/utils/NamedObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/NamedObjectProduct.java
@@ -18,9 +18,6 @@ package sevenUnits.utils;
import java.util.Map;
-import sevenUnits.unit.NameSymbol;
-import sevenUnits.unit.Nameable;
-
/**
* An ObjectProduct with name(s) and/or a symbol. Can be created with the
* {@link ObjectProduct#withName} method.
@@ -43,4 +40,8 @@ public class NamedObjectProduct<T> extends ObjectProduct<T>
return this.nameSymbol;
}
+ @Override
+ public String toString() {
+ return this.nameSymbol.toString() + ", " + super.toString();
+ }
}
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index d4f88b9..926ce10 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.java
@@ -26,8 +26,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
-import sevenUnits.unit.NameSymbol;
-
/**
* An immutable product of multiple objects of a type, such as base units. The
* objects can be multiplied and exponentiated.
@@ -246,7 +244,9 @@ public class ObjectProduct<T> {
*/
@Override
public String toString() {
- return this.toString(Object::toString);
+ return this.toString(o -> o instanceof Nameable
+ ? ((Nameable) o).getNameSymbol().shortName()
+ : o.toString());
}
/**