From 830fba1995229ee3111147b98374737d27925e3c Mon Sep 17 00:00:00 2001 From: Chris Hennick Date: Sat, 12 Aug 2017 21:35:35 +0000 Subject: [PATCH 1/3] Somehow getting formatting changes again! --- .../java/tec/uom/se/AbstractConverter.java | 562 ++--- .../java/tec/uom/se/AbstractQuantity.java | 838 +++---- .../tec/uom/se/AbstractSystemOfUnits.java | 536 ++--- src/main/java/tec/uom/se/AbstractUnit.java | 1026 ++++----- .../java/tec/uom/se/ComparableQuantity.java | 384 ++-- src/main/java/tec/uom/se/ComparableUnit.java | 136 +- .../tec/uom/se/format/AbstractUnitFormat.java | 306 +-- .../tec/uom/se/format/ConverterFormatter.java | 450 ++-- .../uom/se/format/DefaultQuantityFormat.java | 208 +- .../java/tec/uom/se/format/EBNFHelper.java | 636 +++--- .../tec/uom/se/format/EBNFUnitFormat.java | 566 ++--- .../tec/uom/se/format/FormatBehavior.java | 104 +- .../tec/uom/se/format/LocalUnitFormat.java | 1226 +++++------ .../se/format/NumberSpaceQuantityFormat.java | 234 +- .../tec/uom/se/format/QuantityFormat.java | 434 ++-- .../tec/uom/se/format/SimpleUnitFormat.java | 1940 ++++++++--------- .../java/tec/uom/se/format/SymbolMap.java | 496 ++--- .../java/tec/uom/se/format/UnitStyle.java | 136 +- .../tec/uom/se/function/AddConverter.java | 276 +-- .../java/tec/uom/se/function/Converter.java | 110 +- .../tec/uom/se/function/ExpConverter.java | 278 +-- .../tec/uom/se/function/LogConverter.java | 272 +-- .../uom/se/function/MultiplyConverter.java | 278 +-- .../tec/uom/se/function/NaturalOrder.java | 134 +- .../uom/se/function/PiDivisorConverter.java | 212 +- .../se/function/PiMultiplierConverter.java | 348 +-- .../uom/se/function/QuantityConverter.java | 116 +- .../uom/se/function/QuantityFunctions.java | 580 ++--- .../function/QuantitySummaryStatistics.java | 536 ++--- .../uom/se/function/RationalConverter.java | 504 ++--- .../tec/uom/se/function/package-info.java | 70 +- .../internal/DefaultSystemOfUnitsService.java | 134 +- .../se/internal/format/DefaultCharStream.java | 882 ++++---- .../format/DefaultUnitFormatService.java | 190 +- .../format/LocalUnitFormatParser.java | 1810 +++++++-------- .../tec/uom/se/internal/format/Token.java | 288 +-- .../se/internal/format/TokenException.java | 396 ++-- .../uom/se/internal/format/TokenMgrError.java | 326 +-- .../se/internal/format/UnitFormatParser.java | 1800 +++++++-------- .../internal/format/UnitTokenConstants.java | 178 +- .../se/internal/format/UnitTokenManager.java | 922 ++++---- .../format/l10n/BundleToMapAdapter.java | 144 +- .../l10n/MultiPropertyResourceBundle.java | 420 ++-- .../l10n/ResourceBundleEnumeration.java | 198 +- src/main/java/tec/uom/se/package-info.java | 220 +- .../tec/uom/se/quantity/ByteQuantity.java | 280 +-- .../tec/uom/se/quantity/DecimalQuantity.java | 320 +-- .../se/quantity/DefaultQuantityFactory.java | 362 +-- .../tec/uom/se/quantity/DoubleQuantity.java | 318 +-- .../tec/uom/se/quantity/FloatQuantity.java | 336 +-- .../tec/uom/se/quantity/IntegerQuantity.java | 288 +-- .../tec/uom/se/quantity/LongQuantity.java | 284 +-- .../tec/uom/se/quantity/NumberQuantity.java | 492 ++--- .../uom/se/quantity/ProxyQuantityFactory.java | 592 ++--- .../java/tec/uom/se/quantity/Quantities.java | 214 +- .../uom/se/quantity/QuantityDimension.java | 598 ++--- .../tec/uom/se/quantity/QuantityRange.java | 294 +-- .../tec/uom/se/quantity/ShortQuantity.java | 280 +-- .../se/quantity/time/TemporalQuantity.java | 602 ++--- .../uom/se/quantity/time/TimeQuantities.java | 366 ++-- .../se/quantity/time/TimeUnitQuantity.java | 654 +++--- .../tec/uom/se/quantity/time/TimedData.java | 300 +-- .../tec/uom/se/spi/AbstractMeasurement.java | 420 ++-- .../java/tec/uom/se/spi/DimensionalModel.java | 286 +-- .../java/tec/uom/se/spi/NumberComparator.java | 290 +-- src/main/java/tec/uom/se/spi/Range.java | 364 ++-- .../java/tec/uom/se/spi/StandardModel.java | 270 +-- .../java/tec/uom/se/unit/AlternateUnit.java | 266 +-- .../java/tec/uom/se/unit/AnnotatedUnit.java | 292 +-- src/main/java/tec/uom/se/unit/BaseUnit.java | 302 +-- .../java/tec/uom/se/unit/MetricPrefix.java | 752 +++---- .../java/tec/uom/se/unit/ProductElement.java | 192 +- .../java/tec/uom/se/unit/ProductUnit.java | 1048 ++++----- .../java/tec/uom/se/unit/TransformedUnit.java | 416 ++-- src/main/java/tec/uom/se/unit/Units.java | 918 ++++---- .../java/tec/uom/se/unit/package-info.java | 220 +- src/test/java/tec/uom/se/AbsUnitTest.java | 144 +- .../tec/uom/se/format/EBNFFormatTest.java | 244 +-- .../tec/uom/se/format/LocalFormatTest.java | 158 +- .../tec/uom/se/format/LocalMessagesTest.java | 148 +- .../tec/uom/se/format/QuantityFormatTest.java | 230 +- .../tec/uom/se/format/SimpleFormatTest.java | 220 +- .../java/tec/uom/se/format/SymbolMapTest.java | 174 +- .../tec/uom/se/format/UnitFormatTest.java | 378 ++-- .../tec/uom/se/function/AddConverterTest.java | 174 +- .../tec/uom/se/function/ExpConverterTest.java | 166 +- .../tec/uom/se/function/LogConverterTest.java | 166 +- .../se/function/MultiplyConverterTest.java | 182 +- .../se/function/PiDivisorConverterTest.java | 158 +- .../function/PiMultiplierConverterTest.java | 200 +- .../function/QuantityFunctionsFilterTest.java | 430 ++-- .../function/QuantityFunctionsGroupTest.java | 224 +- .../QuantityFunctionsReducerTest.java | 268 +-- .../function/QuantityFunctionsSortTest.java | 294 +-- .../QuantitySummaryStatisticsTest.java | 268 +-- .../uom/se/function/UnitConverterTest.java | 158 +- .../uom/se/internal/format/MessagesTest.java | 102 +- .../format/UnitFormatServiceTest.java | 150 +- .../internal/format/l10n/ResourcesTest.java | 132 +- .../tec/uom/se/quantity/ArithmeticTest.java | 152 +- .../uom/se/quantity/ByteQuantityBaseTest.java | 266 +-- .../tec/uom/se/quantity/ByteQuantityTest.java | 222 +- .../DecimalComparableQuantityTest.java | 506 ++--- .../uom/se/quantity/DecimalQuantityTest.java | 282 +-- .../DoubleComparableQuantityTest.java | 472 ++-- .../uom/se/quantity/DoubleQuantityTest.java | 318 +-- .../uom/se/quantity/FloatQuantityTest.java | 238 +- .../uom/se/quantity/IntegerQuantityTest.java | 224 +- .../tec/uom/se/quantity/LongQuantityTest.java | 208 +- .../NumberComparableQuantityTest.java | 490 ++--- .../uom/se/quantity/NumberQuantityTest.java | 360 +-- .../tec/uom/se/quantity/QuantitiesTest.java | 206 +- .../quantity/QuantityFactoryProviderTest.java | 186 +- .../uom/se/quantity/QuantityRangeTest.java | 180 +- .../se/quantity/ShortQuantityBaseTest.java | 266 +-- .../uom/se/quantity/ShortQuantityTest.java | 222 +- .../time/TimeQuantitiesConcurrentTest.java | 324 +-- .../se/quantity/time/TimeQuantitiesTest.java | 358 +-- .../java/tec/uom/se/spi/MeasurementTest.java | 108 +- src/test/java/tec/uom/se/spi/RangeTest.java | 168 +- src/test/java/tec/uom/se/spi/ServiceTest.java | 132 +- .../uom/se/spi/SystemOfUnitsServiceTest.java | 134 +- .../java/tec/uom/se/unit/BaseUnitTest.java | 328 +-- src/test/java/tec/uom/se/unit/PrefixTest.java | 368 ++-- src/test/java/tec/uom/se/unit/UnitsTest.java | 800 +++---- 125 files changed, 23371 insertions(+), 23371 deletions(-) diff --git a/src/main/java/tec/uom/se/AbstractConverter.java b/src/main/java/tec/uom/se/AbstractConverter.java index e3a07aab..b2619c6e 100644 --- a/src/main/java/tec/uom/se/AbstractConverter.java +++ b/src/main/java/tec/uom/se/AbstractConverter.java @@ -1,287 +1,287 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se; - -import javax.measure.UnitConverter; - -import tec.uom.se.function.Converter; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - *

- * The base class for our {@link UnitConverter} implementations. - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, August 9, 2016 - * @since 1.0 - */ -public abstract class AbstractConverter implements UnitConverter, Converter, Serializable { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se; + +import javax.measure.UnitConverter; + +import tec.uom.se.function.Converter; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + *

+ * The base class for our {@link UnitConverter} implementations. + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, August 9, 2016 + * @since 1.0 + */ +public abstract class AbstractConverter implements UnitConverter, Converter, Serializable { + /** * - */ - private static final long serialVersionUID = 5790242858468427131L; - - /** - * The ratio of the circumference of a circle to its diameter. - **/ - protected static final double PI = 3.1415926535897932384626433832795; - - /** - * Holds identity converter. - */ - public static final AbstractConverter IDENTITY = new Identity(); - - /** - * DefaultQuantityFactory constructor. - */ - protected AbstractConverter() { - } - - /** - * Concatenates this physics converter with another physics converter. The resulting converter is equivalent to first converting by the specified - * converter (right converter), and then converting by this converter (left converter). - * - * @param that - * the other converter. - * @return the concatenation of this converter with that converter. - */ - public AbstractConverter concatenate(AbstractConverter that) { - return (that == IDENTITY) ? this : new Pair(this, that); - } - - @Override - public boolean isIdentity() { - return false; - } - - @Override - public abstract boolean equals(Object cvtr); - - @Override - public abstract int hashCode(); - - @Override - public abstract AbstractConverter inverse(); - - @Override - public UnitConverter concatenate(UnitConverter converter) { - return (converter == IDENTITY) ? this : new Pair(this, converter); - } - - @Override - public List getConversionSteps() { - List converters = new ArrayList<>(); - converters.add(this); - return converters; - } - - /** - * @throws IllegalArgumentException - * if the value is null. - */ - public Number convert(Number value) { - if (value instanceof BigDecimal) { - return convert((BigDecimal) value, MathContext.DECIMAL128); - } - if (value != null) { - return convert(value.doubleValue()); - } else { - throw new IllegalArgumentException("Value cannot be null"); - } - } - - @Override - public abstract double convert(double value); - - public abstract BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException; - - /** - * This class represents the identity converter (singleton). - */ - private static final class Identity extends AbstractConverter { - + */ + private static final long serialVersionUID = 5790242858468427131L; + + /** + * The ratio of the circumference of a circle to its diameter. + **/ + protected static final double PI = 3.1415926535897932384626433832795; + + /** + * Holds identity converter. + */ + public static final AbstractConverter IDENTITY = new Identity(); + + /** + * DefaultQuantityFactory constructor. + */ + protected AbstractConverter() { + } + + /** + * Concatenates this physics converter with another physics converter. The resulting converter is equivalent to first converting by the specified + * converter (right converter), and then converting by this converter (left converter). + * + * @param that + * the other converter. + * @return the concatenation of this converter with that converter. + */ + public AbstractConverter concatenate(AbstractConverter that) { + return (that == IDENTITY) ? this : new Pair(this, that); + } + + @Override + public boolean isIdentity() { + return false; + } + + @Override + public abstract boolean equals(Object cvtr); + + @Override + public abstract int hashCode(); + + @Override + public abstract AbstractConverter inverse(); + + @Override + public UnitConverter concatenate(UnitConverter converter) { + return (converter == IDENTITY) ? this : new Pair(this, converter); + } + + @Override + public List getConversionSteps() { + List converters = new ArrayList<>(); + converters.add(this); + return converters; + } + + /** + * @throws IllegalArgumentException + * if the value is null. + */ + public Number convert(Number value) { + if (value instanceof BigDecimal) { + return convert((BigDecimal) value, MathContext.DECIMAL128); + } + if (value != null) { + return convert(value.doubleValue()); + } else { + throw new IllegalArgumentException("Value cannot be null"); + } + } + + @Override + public abstract double convert(double value); + + public abstract BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException; + + /** + * This class represents the identity converter (singleton). + */ + private static final class Identity extends AbstractConverter { + /** * - */ - private static final long serialVersionUID = -4460463244427587361L; - - @Override - public boolean isIdentity() { - return true; - } - - @Override - public Identity inverse() { - return this; - } - - @Override - public double convert(double value) { - return value; - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) { - return value; - } - - @Override - public UnitConverter concatenate(UnitConverter converter) { - return converter; - } - - @Override - public boolean equals(Object cvtr) { - return (cvtr instanceof Identity); - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public boolean isLinear() { - return true; - } - } - - /** - * This class represents converters made up of two or more separate converters (in matrix notation [pair] = [left] x [right]). - */ - public static final class Pair extends AbstractConverter implements Serializable { - + */ + private static final long serialVersionUID = -4460463244427587361L; + + @Override + public boolean isIdentity() { + return true; + } + + @Override + public Identity inverse() { + return this; + } + + @Override + public double convert(double value) { + return value; + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) { + return value; + } + + @Override + public UnitConverter concatenate(UnitConverter converter) { + return converter; + } + + @Override + public boolean equals(Object cvtr) { + return (cvtr instanceof Identity); + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean isLinear() { + return true; + } + } + + /** + * This class represents converters made up of two or more separate converters (in matrix notation [pair] = [left] x [right]). + */ + public static final class Pair extends AbstractConverter implements Serializable { + /** * - */ - private static final long serialVersionUID = -123063827821728331L; - - /** - * Holds the first converter. - */ - private final UnitConverter left; - - /** - * Holds the second converter. - */ - private final UnitConverter right; - - /** - * Creates a pair converter resulting from the combined transformation of the specified converters. - * - * @param left - * the left converter, not null. - * @param right - * the right converter. - * @throws IllegalArgumentException - * if either the left or right converter are null - */ - public Pair(UnitConverter left, UnitConverter right) { - if (left != null && right != null) { - this.left = left; - this.right = right; - } else { - throw new IllegalArgumentException("Converters cannot be null"); - } - } - - @Override - public boolean isLinear() { - return left.isLinear() && right.isLinear(); - } - - @Override - public boolean isIdentity() { - return false; - } - - @Override - public List getConversionSteps() { - final List steps = new ArrayList<>(); - List leftCompound = left.getConversionSteps(); - List rightCompound = right.getConversionSteps(); - steps.addAll(leftCompound); - steps.addAll(rightCompound); - return steps; - } - - @Override - public Pair inverse() { - return new Pair(right.inverse(), left.inverse()); - } - - @Override - public double convert(double value) { - return left.convert(right.convert(value)); - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) { - if (right instanceof AbstractConverter) { - return ((AbstractConverter) left).convert(((AbstractConverter) right).convert(value, ctx), ctx); - } - return (BigDecimal) left.convert(right.convert(value)); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof Pair) { - Pair that = (Pair) obj; - return Objects.equals(left, that.left) && Objects.equals(right, that.right); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(left, right); - } - - public UnitConverter getLeft() { - return left; - } - - public UnitConverter getRight() { - return right; - } - } -} + */ + private static final long serialVersionUID = -123063827821728331L; + + /** + * Holds the first converter. + */ + private final UnitConverter left; + + /** + * Holds the second converter. + */ + private final UnitConverter right; + + /** + * Creates a pair converter resulting from the combined transformation of the specified converters. + * + * @param left + * the left converter, not null. + * @param right + * the right converter. + * @throws IllegalArgumentException + * if either the left or right converter are null + */ + public Pair(UnitConverter left, UnitConverter right) { + if (left != null && right != null) { + this.left = left; + this.right = right; + } else { + throw new IllegalArgumentException("Converters cannot be null"); + } + } + + @Override + public boolean isLinear() { + return left.isLinear() && right.isLinear(); + } + + @Override + public boolean isIdentity() { + return false; + } + + @Override + public List getConversionSteps() { + final List steps = new ArrayList<>(); + List leftCompound = left.getConversionSteps(); + List rightCompound = right.getConversionSteps(); + steps.addAll(leftCompound); + steps.addAll(rightCompound); + return steps; + } + + @Override + public Pair inverse() { + return new Pair(right.inverse(), left.inverse()); + } + + @Override + public double convert(double value) { + return left.convert(right.convert(value)); + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) { + if (right instanceof AbstractConverter) { + return ((AbstractConverter) left).convert(((AbstractConverter) right).convert(value, ctx), ctx); + } + return (BigDecimal) left.convert(right.convert(value)); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Pair) { + Pair that = (Pair) obj; + return Objects.equals(left, that.left) && Objects.equals(right, that.right); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(left, right); + } + + public UnitConverter getLeft() { + return left; + } + + public UnitConverter getRight() { + return right; + } + } +} diff --git a/src/main/java/tec/uom/se/AbstractQuantity.java b/src/main/java/tec/uom/se/AbstractQuantity.java index 6a4c7ace..4bea5f38 100644 --- a/src/main/java/tec/uom/se/AbstractQuantity.java +++ b/src/main/java/tec/uom/se/AbstractQuantity.java @@ -1,77 +1,77 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; -import java.util.Comparator; -import java.util.Objects; - -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.UnitConverter; -import javax.measure.quantity.Dimensionless; - -import tec.uom.lib.common.function.UnitSupplier; -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.format.QuantityFormat; -import tec.uom.se.function.NaturalOrder; -import tec.uom.se.quantity.Quantities; - -/** - *

- * This class represents the immutable result of a scalar measurement stated in a known unit. - *

- * - *

- * To avoid any loss of precision, known exact quantities (e.g. physical constants) should not be created from double constants but from - * their decimal representation.
+/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.util.Comparator; +import java.util.Objects; + +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.UnitConverter; +import javax.measure.quantity.Dimensionless; + +import tec.uom.lib.common.function.UnitSupplier; +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.format.QuantityFormat; +import tec.uom.se.function.NaturalOrder; +import tec.uom.se.quantity.Quantities; + +/** + *

+ * This class represents the immutable result of a scalar measurement stated in a known unit. + *

+ * + *

+ * To avoid any loss of precision, known exact quantities (e.g. physical constants) should not be created from double constants but from + * their decimal representation.
* * public static final Quantity<Velocity> C = NumberQuantity.parse("299792458 m/s").asType(Velocity.class); * // Speed of Light (exact). - * - *

- * - *

- * Quantities can be converted to different units.
+ * + *

+ * + *

+ * Quantities can be converted to different units.
* * Quantity<Velocity> milesPerHour = C.to(MILES_PER_HOUR); // Use double implementation (fast). * System.out.println(milesPerHour); * * > 670616629.3843951 m/h - * - *

- * - *

- * Applications may sub-class {@link AbstractQuantity} for particular quantity types.
+ * + *

+ * + *

+ * Applications may sub-class {@link AbstractQuantity} for particular quantity types.
* * // Quantity of type Mass based on double primitive types.
* public class MassAmount extends AbstractQuantity<Mass> {
@@ -96,363 +96,363 @@ * // Specializations of complex numbers measurements.
* public final class Current extends ComplexQuantity<ElectricCurrent> {...}
* public final class Tension extends ComplexQuantity<ElectricPotential> {...}
- *
- *

- * - *

- * All instances of this class shall be immutable. - *

- * - * @author Werner Keil - * @version 1.0.6, August 7, 2017 - * @since 1.0 - */ -@SuppressWarnings("unchecked") -public abstract class AbstractQuantity> implements ComparableQuantity, UnitSupplier, ValueSupplier { - + * + *

+ * + *

+ * All instances of this class shall be immutable. + *

+ * + * @author Werner Keil + * @version 1.0.6, August 7, 2017 + * @since 1.0 + */ +@SuppressWarnings("unchecked") +public abstract class AbstractQuantity> implements ComparableQuantity, UnitSupplier, ValueSupplier { + /** * - */ - private static final long serialVersionUID = 293852425369811882L; - - private final Unit unit; - - /** - * Holds a dimensionless quantity of none (exact). - */ - public static final Quantity NONE = Quantities.getQuantity(0, AbstractUnit.ONE); - - /** - * Holds a dimensionless quantity of one (exact). - */ - public static final Quantity ONE = Quantities.getQuantity(1, AbstractUnit.ONE); - - /** - * constructor. - */ - protected AbstractQuantity(Unit unit) { - this.unit = unit; - } - - /** - * Returns the numeric value of the quantity. - * - * @return the quantity value. - */ - @Override - public abstract Number getValue(); - - /** - * Returns the measurement unit. - * - * @return the measurement unit. - */ - @Override - public Unit getUnit() { - return unit; - } - - /** - * Convenient method equivalent to {@link #to(javax.measure.unit.Unit) to(this.getUnit().toSI())}. - * - * @return this measure or a new measure equivalent to this measure but stated in SI units. - * @throws ArithmeticException - * if the result is inexact and the quotient has a non-terminating decimal expansion. - */ - public Quantity toSI() { - return to(this.getUnit().getSystemUnit()); - } - - /** - * Returns this measure after conversion to specified unit. The default implementation returns Measure.valueOf(doubleValue(unit), unit) - * . If this measure is already stated in the specified unit, then this measure is returned and no conversion is performed. - * - * @param unit - * the unit in which the returned measure is stated. - * @return this measure or a new measure equivalent to this measure but stated in the specified unit. - * @throws ArithmeticException - * if the result is inexact and the quotient has a non-terminating decimal expansion. - */ - @Override - public ComparableQuantity to(Unit unit) { - if (unit.equals(this.getUnit())) { - return this; - } - UnitConverter t = getUnit().getConverterTo(unit); - Number convertedValue = t.convert(getValue()); - return Quantities.getQuantity(convertedValue, unit); - } - - /** - * Returns this measure after conversion to specified unit. The default implementation returns - * Measure.valueOf(decimalValue(unit, ctx), unit). If this measure is already stated in the specified unit, then this measure is - * returned and no conversion is performed. - * - * @param unit - * the unit in which the returned measure is stated. - * @param ctx - * the math context to use for conversion. - * @return this measure or a new measure equivalent to this measure but stated in the specified unit. - * @throws ArithmeticException - * if the result is inexact but the rounding mode is UNNECESSARY or mathContext.precision == 0 and the quotient - * has a non-terminating decimal expansion. - */ - public Quantity to(Unit unit, MathContext ctx) { - if (unit.equals(this.getUnit())) { - return this; - } - return Quantities.getQuantity(decimalValue(unit, ctx), unit); - } - - @Override - public boolean isGreaterThan(Quantity that) { - return this.compareTo(that) > 0; - } - - @Override - public boolean isGreaterThanOrEqualTo(Quantity that) { - return this.compareTo(that) >= 0; - } - - @Override - public boolean isLessThan(Quantity that) { - return this.compareTo(that) < 0; - } - - @Override - public boolean isLessThanOrEqualTo(Quantity that) { - return this.compareTo(that) <= 0; - } - - @Override - public boolean isEquivalentOf(Quantity that) { - return this.compareTo(that) == 0; - } - - @Override - public boolean isEquivalentTo(Quantity that) { - return isEquivalentOf(that); - } - - /** - * Compares this measure to the specified Measurement quantity. The default implementation compares the {@link AbstractQuantity#doubleValue(Unit)} - * of both this measure and the specified Measurement stated in the same unit (this measure's {@link #getUnit() unit}). - * - * @return a negative integer, zero, or a positive integer as this measure is less than, equal to, or greater than the specified Measurement - * quantity. - * @see {@link NaturalOrder} - */ - @Override - public int compareTo(Quantity that) { - final Comparator> comparator = new NaturalOrder<>(); - return comparator.compare(this, that); - } - - /** - * Compares this quantity against the specified object for strict equality (same unit and same amount). - * - *

- * Similarly to the {@link BigDecimal#equals} method which consider 2.0 and 2.00 as different objects because of different internal scales, - * quantities such as Quantities.getQuantity(3.0, KILOGRAM) Quantities.getQuantity(3, KILOGRAM) and - * Quantities.getQuantity("3 kg") might not be considered equals because of possible differences in their implementations. - *

- * - *

- * To compare quantities stated using different units or using different amount implementations the {@link #compareTo compareTo} or - * {@link #equals(javax.measure.Quantity, double, javax.measure.unit.Unit) equals(Quantity, epsilon, epsilonUnit)} methods should be used. - *

- * - * @param obj - * the object to compare with. + */ + private static final long serialVersionUID = 293852425369811882L; + + private final Unit unit; + + /** + * Holds a dimensionless quantity of none (exact). + */ + public static final Quantity NONE = Quantities.getQuantity(0, AbstractUnit.ONE); + + /** + * Holds a dimensionless quantity of one (exact). + */ + public static final Quantity ONE = Quantities.getQuantity(1, AbstractUnit.ONE); + + /** + * constructor. + */ + protected AbstractQuantity(Unit unit) { + this.unit = unit; + } + + /** + * Returns the numeric value of the quantity. + * + * @return the quantity value. + */ + @Override + public abstract Number getValue(); + + /** + * Returns the measurement unit. + * + * @return the measurement unit. + */ + @Override + public Unit getUnit() { + return unit; + } + + /** + * Convenient method equivalent to {@link #to(javax.measure.unit.Unit) to(this.getUnit().toSI())}. + * + * @return this measure or a new measure equivalent to this measure but stated in SI units. + * @throws ArithmeticException + * if the result is inexact and the quotient has a non-terminating decimal expansion. + */ + public Quantity toSI() { + return to(this.getUnit().getSystemUnit()); + } + + /** + * Returns this measure after conversion to specified unit. The default implementation returns Measure.valueOf(doubleValue(unit), unit) + * . If this measure is already stated in the specified unit, then this measure is returned and no conversion is performed. + * + * @param unit + * the unit in which the returned measure is stated. + * @return this measure or a new measure equivalent to this measure but stated in the specified unit. + * @throws ArithmeticException + * if the result is inexact and the quotient has a non-terminating decimal expansion. + */ + @Override + public ComparableQuantity to(Unit unit) { + if (unit.equals(this.getUnit())) { + return this; + } + UnitConverter t = getUnit().getConverterTo(unit); + Number convertedValue = t.convert(getValue()); + return Quantities.getQuantity(convertedValue, unit); + } + + /** + * Returns this measure after conversion to specified unit. The default implementation returns + * Measure.valueOf(decimalValue(unit, ctx), unit). If this measure is already stated in the specified unit, then this measure is + * returned and no conversion is performed. + * + * @param unit + * the unit in which the returned measure is stated. + * @param ctx + * the math context to use for conversion. + * @return this measure or a new measure equivalent to this measure but stated in the specified unit. + * @throws ArithmeticException + * if the result is inexact but the rounding mode is UNNECESSARY or mathContext.precision == 0 and the quotient + * has a non-terminating decimal expansion. + */ + public Quantity to(Unit unit, MathContext ctx) { + if (unit.equals(this.getUnit())) { + return this; + } + return Quantities.getQuantity(decimalValue(unit, ctx), unit); + } + + @Override + public boolean isGreaterThan(Quantity that) { + return this.compareTo(that) > 0; + } + + @Override + public boolean isGreaterThanOrEqualTo(Quantity that) { + return this.compareTo(that) >= 0; + } + + @Override + public boolean isLessThan(Quantity that) { + return this.compareTo(that) < 0; + } + + @Override + public boolean isLessThanOrEqualTo(Quantity that) { + return this.compareTo(that) <= 0; + } + + @Override + public boolean isEquivalentOf(Quantity that) { + return this.compareTo(that) == 0; + } + + @Override + public boolean isEquivalentTo(Quantity that) { + return isEquivalentOf(that); + } + + /** + * Compares this measure to the specified Measurement quantity. The default implementation compares the {@link AbstractQuantity#doubleValue(Unit)} + * of both this measure and the specified Measurement stated in the same unit (this measure's {@link #getUnit() unit}). + * + * @return a negative integer, zero, or a positive integer as this measure is less than, equal to, or greater than the specified Measurement + * quantity. + * @see {@link NaturalOrder} + */ + @Override + public int compareTo(Quantity that) { + final Comparator> comparator = new NaturalOrder<>(); + return comparator.compare(this, that); + } + + /** + * Compares this quantity against the specified object for strict equality (same unit and same amount). + * + *

+ * Similarly to the {@link BigDecimal#equals} method which consider 2.0 and 2.00 as different objects because of different internal scales, + * quantities such as Quantities.getQuantity(3.0, KILOGRAM) Quantities.getQuantity(3, KILOGRAM) and + * Quantities.getQuantity("3 kg") might not be considered equals because of possible differences in their implementations. + *

+ * + *

+ * To compare quantities stated using different units or using different amount implementations the {@link #compareTo compareTo} or + * {@link #equals(javax.measure.Quantity, double, javax.measure.unit.Unit) equals(Quantity, epsilon, epsilonUnit)} methods should be used. + *

+ * + * @param obj + * the object to compare with. * @return this.getUnit.equals(obj.getUnit()) - * && this.getValue().equals(obj.getValue()) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof AbstractQuantity) { - AbstractQuantity that = (AbstractQuantity) obj; - return Objects.equals(getUnit(), that.getUnit()) && Objects.equals(getValue(), that.getValue()); - } - return false; - } - - /** - * Compares this quantity and the specified quantity to the given accuracy. Quantities are considered approximately equals if their absolute - * differences when stated in the same specified unit is less than the specified epsilon. - * - * @param that - * the quantity to compare with. - * @param epsilon - * the absolute error stated in epsilonUnit. - * @param epsilonUnit - * the epsilon unit. - * @return abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon - */ - public boolean equals(AbstractQuantity that, double epsilon, Unit epsilonUnit) { - return Math.abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon; - } - - /** - * Returns the hash code for this quantity. - * - * @return the hash code value. - */ - @Override - public int hashCode() { - return Objects.hash(getUnit(), getValue()); - } - - public abstract boolean isBig(); - - /** - * Returns the String representation of this quantity. The string produced for a given quantity is always the same; it is not affected - * by locale. This means that it can be used as a canonical string representation for exchanging quantity, or as a key for a Hashtable, etc. - * Locale-sensitive quantity formatting and parsing is handled by the {@link MeasurementFormat} class and its subclasses. - * - * @return UnitFormat.getInternational().format(this) - */ - @Override - public String toString() { - return String.valueOf(getValue()) + " " + String.valueOf(getUnit()); - } - - public abstract BigDecimal decimalValue(Unit unit, MathContext ctx) throws ArithmeticException; - - public abstract double doubleValue(Unit unit) throws ArithmeticException; - - public final int intValue(Unit unit) throws ArithmeticException { - long longValue = longValue(unit); - if ((longValue < Integer.MIN_VALUE) || (longValue > Integer.MAX_VALUE)) { - throw new ArithmeticException("Cannot convert " + longValue + " to int (overflow)"); - } - return (int) longValue; - } - - protected long longValue(Unit unit) throws ArithmeticException { - double result = doubleValue(unit); - if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE)) { - throw new ArithmeticException("Overflow (" + result + ")"); - } - return (long) result; - } - - protected final float floatValue(Unit unit) { - return (float) doubleValue(unit); - } - - @Override - public , E extends Quantity> ComparableQuantity divide(Quantity that, Class asTypeQuantity) { - - return divide(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity)); - - } - - @Override - public , E extends Quantity> ComparableQuantity multiply(Quantity that, Class asTypeQuantity) { - return multiply(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity)); - } - - @Override - public > ComparableQuantity inverse(Class quantityClass) { - return inverse().asType(quantityClass); - } - - /** - * Casts this quantity to a parameterized quantity of specified nature or throw a ClassCastException if the dimension of the specified - * quantity and its unit's dimension do not match. For example:
+ * && this.getValue().equals(obj.getValue()) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof AbstractQuantity) { + AbstractQuantity that = (AbstractQuantity) obj; + return Objects.equals(getUnit(), that.getUnit()) && Objects.equals(getValue(), that.getValue()); + } + return false; + } + + /** + * Compares this quantity and the specified quantity to the given accuracy. Quantities are considered approximately equals if their absolute + * differences when stated in the same specified unit is less than the specified epsilon. + * + * @param that + * the quantity to compare with. + * @param epsilon + * the absolute error stated in epsilonUnit. + * @param epsilonUnit + * the epsilon unit. + * @return abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon + */ + public boolean equals(AbstractQuantity that, double epsilon, Unit epsilonUnit) { + return Math.abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon; + } + + /** + * Returns the hash code for this quantity. + * + * @return the hash code value. + */ + @Override + public int hashCode() { + return Objects.hash(getUnit(), getValue()); + } + + public abstract boolean isBig(); + + /** + * Returns the String representation of this quantity. The string produced for a given quantity is always the same; it is not affected + * by locale. This means that it can be used as a canonical string representation for exchanging quantity, or as a key for a Hashtable, etc. + * Locale-sensitive quantity formatting and parsing is handled by the {@link MeasurementFormat} class and its subclasses. + * + * @return UnitFormat.getInternational().format(this) + */ + @Override + public String toString() { + return String.valueOf(getValue()) + " " + String.valueOf(getUnit()); + } + + public abstract BigDecimal decimalValue(Unit unit, MathContext ctx) throws ArithmeticException; + + public abstract double doubleValue(Unit unit) throws ArithmeticException; + + public final int intValue(Unit unit) throws ArithmeticException { + long longValue = longValue(unit); + if ((longValue < Integer.MIN_VALUE) || (longValue > Integer.MAX_VALUE)) { + throw new ArithmeticException("Cannot convert " + longValue + " to int (overflow)"); + } + return (int) longValue; + } + + protected long longValue(Unit unit) throws ArithmeticException { + double result = doubleValue(unit); + if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE)) { + throw new ArithmeticException("Overflow (" + result + ")"); + } + return (long) result; + } + + protected final float floatValue(Unit unit) { + return (float) doubleValue(unit); + } + + @Override + public , E extends Quantity> ComparableQuantity divide(Quantity that, Class asTypeQuantity) { + + return divide(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity)); + + } + + @Override + public , E extends Quantity> ComparableQuantity multiply(Quantity that, Class asTypeQuantity) { + return multiply(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity)); + } + + @Override + public > ComparableQuantity inverse(Class quantityClass) { + return inverse().asType(quantityClass); + } + + /** + * Casts this quantity to a parameterized quantity of specified nature or throw a ClassCastException if the dimension of the specified + * quantity and its unit's dimension do not match. For example:
* * Quantity length = AbstractQuantity.parse("2 km").asType(Length.class); - * - * - * @param type - * the quantity class identifying the nature of the quantity. - * @return this quantity parameterized with the specified type. - * @throws ClassCastException - * if the dimension of this unit is different from the specified quantity dimension. - * @throws UnsupportedOperationException - * if the specified quantity class does not have a public static field named "UNIT" holding the SI unit for the quantity. - * @see Unit#asType(Class) - */ - public final > ComparableQuantity asType(Class type) throws ClassCastException { - this.getUnit().asType(type); // Raises ClassCastException if dimension - // mismatches. - return (ComparableQuantity) this; - } - - /** - * Returns the quantity of unknown type corresponding to the specified representation. This method can be used to parse dimensionless quantities.
+ * + * + * @param type + * the quantity class identifying the nature of the quantity. + * @return this quantity parameterized with the specified type. + * @throws ClassCastException + * if the dimension of this unit is different from the specified quantity dimension. + * @throws UnsupportedOperationException + * if the specified quantity class does not have a public static field named "UNIT" holding the SI unit for the quantity. + * @see Unit#asType(Class) + */ + public final > ComparableQuantity asType(Class type) throws ClassCastException { + this.getUnit().asType(type); // Raises ClassCastException if dimension + // mismatches. + return (ComparableQuantity) this; + } + + /** + * Returns the quantity of unknown type corresponding to the specified representation. This method can be used to parse dimensionless quantities.
* * Quatity proportion = AbstractQuantity.parse("0.234").asType(Dimensionless.class); - * - * - *

- * Note: This method handles only {@link SimpleUnitFormat#getStandard standard} unit format. Locale-sensitive quantity parsing is currently not - * supported. - *

- * - * @param csq - * the decimal value and its unit (if any) separated by space(s). - * @return QuantityFormat.getInstance().parse(csq) - */ - public static Quantity parse(CharSequence csq) { - return QuantityFormat.getInstance().parse(csq); - } - - /** - * Utility class for number comparison and equality - */ - protected static final class Equalizer { - - /** - * Converts a number to {@link BigDecimal} - * - * @param value - * the value to be converted - * @return the value converted - */ - public static BigDecimal toBigDecimal(Number value) { - if (BigDecimal.class.isInstance(value)) { - return BigDecimal.class.cast(value); - } else if (BigInteger.class.isInstance(value)) { - return new BigDecimal(BigInteger.class.cast(value)); - } - return BigDecimal.valueOf(value.doubleValue()); - } - - /** - * Check if the both value has equality number, in other words, 1 is equals to 1.0000 and 1.0. - * - * If the first value is a Number of either Double, Float, Integer, Long, - * Short or Byte it is compared using the respective *value() method of Number. Otherwise it - * is checked, if {@link BigDecimal#compareTo(Object)} is equal to zero. - * - * @param valueA - * the value a - * @param valueB - * the value B - * @return {@link BigDecimal#compareTo(Object)} == zero - */ - public static boolean hasEquality(Number valueA, Number valueB) { - Objects.requireNonNull(valueA); - Objects.requireNonNull(valueB); - - if (valueA instanceof Double && valueB instanceof Double) { - return valueA.doubleValue() == valueB.doubleValue(); - } else if (valueA instanceof Float && valueB instanceof Float) { - return valueA.floatValue() == valueB.floatValue(); - } else if (valueA instanceof Integer && valueB instanceof Integer) { - return valueA.intValue() == valueB.intValue(); - } else if (valueA instanceof Long && valueB instanceof Long) { - return valueA.longValue() == valueB.longValue(); - } else if (valueA instanceof Short && valueB instanceof Short) { - return valueA.shortValue() == valueB.shortValue(); - } else if (valueA instanceof Byte && valueB instanceof Byte) { - return valueA.byteValue() == valueB.byteValue(); - } - return toBigDecimal(valueA).compareTo(toBigDecimal(valueB)) == 0; - } - } -} + * + * + *

+ * Note: This method handles only {@link SimpleUnitFormat#getStandard standard} unit format. Locale-sensitive quantity parsing is currently not + * supported. + *

+ * + * @param csq + * the decimal value and its unit (if any) separated by space(s). + * @return QuantityFormat.getInstance().parse(csq) + */ + public static Quantity parse(CharSequence csq) { + return QuantityFormat.getInstance().parse(csq); + } + + /** + * Utility class for number comparison and equality + */ + protected static final class Equalizer { + + /** + * Converts a number to {@link BigDecimal} + * + * @param value + * the value to be converted + * @return the value converted + */ + public static BigDecimal toBigDecimal(Number value) { + if (BigDecimal.class.isInstance(value)) { + return BigDecimal.class.cast(value); + } else if (BigInteger.class.isInstance(value)) { + return new BigDecimal(BigInteger.class.cast(value)); + } + return BigDecimal.valueOf(value.doubleValue()); + } + + /** + * Check if the both value has equality number, in other words, 1 is equals to 1.0000 and 1.0. + * + * If the first value is a Number of either Double, Float, Integer, Long, + * Short or Byte it is compared using the respective *value() method of Number. Otherwise it + * is checked, if {@link BigDecimal#compareTo(Object)} is equal to zero. + * + * @param valueA + * the value a + * @param valueB + * the value B + * @return {@link BigDecimal#compareTo(Object)} == zero + */ + public static boolean hasEquality(Number valueA, Number valueB) { + Objects.requireNonNull(valueA); + Objects.requireNonNull(valueB); + + if (valueA instanceof Double && valueB instanceof Double) { + return valueA.doubleValue() == valueB.doubleValue(); + } else if (valueA instanceof Float && valueB instanceof Float) { + return valueA.floatValue() == valueB.floatValue(); + } else if (valueA instanceof Integer && valueB instanceof Integer) { + return valueA.intValue() == valueB.intValue(); + } else if (valueA instanceof Long && valueB instanceof Long) { + return valueA.longValue() == valueB.longValue(); + } else if (valueA instanceof Short && valueB instanceof Short) { + return valueA.shortValue() == valueB.shortValue(); + } else if (valueA instanceof Byte && valueB instanceof Byte) { + return valueA.byteValue() == valueB.byteValue(); + } + return toBigDecimal(valueA).compareTo(toBigDecimal(valueB)) == 0; + } + } +} diff --git a/src/main/java/tec/uom/se/AbstractSystemOfUnits.java b/src/main/java/tec/uom/se/AbstractSystemOfUnits.java index 15df4627..65e92b0a 100644 --- a/src/main/java/tec/uom/se/AbstractSystemOfUnits.java +++ b/src/main/java/tec/uom/se/AbstractSystemOfUnits.java @@ -1,121 +1,121 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se; - -import javax.measure.Dimension; -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.spi.SystemOfUnits; - -import tec.uom.lib.common.function.Nameable; -import tec.uom.se.format.SimpleUnitFormat; -import tec.uom.se.format.UnitStyle; - -import static tec.uom.se.format.UnitStyle.*; - -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - *

- * An abstract base class for unit systems. - *

- * - * @author Werner Keil - * @version 1.0.2, November 3, 2016 - * @since 1.0 - */ -public abstract class AbstractSystemOfUnits implements SystemOfUnits, Nameable { - /** - * Holds the units. - */ - protected final Set> units = new HashSet<>(); - - /** - * Holds the mapping quantity to unit. - */ - @SuppressWarnings("rawtypes") - protected final Map, Unit> quantityToUnit = new HashMap<>(); - - protected static final Logger logger = Logger.getLogger(AbstractSystemOfUnits.class.getName()); - - /** - * Adds a new named unit to the collection. - * - * @param unit - * the unit being added. - * @param name - * the name of the unit. - * @return unit. - */ - /* - * @SuppressWarnings("unchecked") private > U addUnit(U - * unit, String name) { if (name != null && unit instanceof AbstractUnit) { - * AbstractUnit aUnit = (AbstractUnit) unit; aUnit.setName(name); - * units.add(aUnit); return (U) aUnit; } units.add(unit); return unit; } - */ - /** - * The natural logarithm. - **/ - protected static final double E = 2.71828182845904523536028747135266; - - /* - * (non-Javadoc) - * - * @see SystemOfUnits#getName() - */ - public abstract String getName(); - - // /////////////////// - // Collection View // - // /////////////////// - @Override - public Set> getUnits() { - return Collections.unmodifiableSet(units); - } - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se; + +import javax.measure.Dimension; +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.spi.SystemOfUnits; + +import tec.uom.lib.common.function.Nameable; +import tec.uom.se.format.SimpleUnitFormat; +import tec.uom.se.format.UnitStyle; + +import static tec.uom.se.format.UnitStyle.*; + +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + *

+ * An abstract base class for unit systems. + *

+ * + * @author Werner Keil + * @version 1.0.2, November 3, 2016 + * @since 1.0 + */ +public abstract class AbstractSystemOfUnits implements SystemOfUnits, Nameable { + /** + * Holds the units. + */ + protected final Set> units = new HashSet<>(); + + /** + * Holds the mapping quantity to unit. + */ + @SuppressWarnings("rawtypes") + protected final Map, Unit> quantityToUnit = new HashMap<>(); + + protected static final Logger logger = Logger.getLogger(AbstractSystemOfUnits.class.getName()); + + /** + * Adds a new named unit to the collection. + * + * @param unit + * the unit being added. + * @param name + * the name of the unit. + * @return unit. + */ + /* + * @SuppressWarnings("unchecked") private > U addUnit(U + * unit, String name) { if (name != null && unit instanceof AbstractUnit) { + * AbstractUnit aUnit = (AbstractUnit) unit; aUnit.setName(name); + * units.add(aUnit); return (U) aUnit; } units.add(unit); return unit; } + */ + /** + * The natural logarithm. + **/ + protected static final double E = 2.71828182845904523536028747135266; + + /* + * (non-Javadoc) + * + * @see SystemOfUnits#getName() + */ + public abstract String getName(); + + // /////////////////// + // Collection View // + // /////////////////// + @Override + public Set> getUnits() { + return Collections.unmodifiableSet(units); + } + @Override public Set> getUnits(Dimension dimension) { return this.getUnits().stream().filter(unit -> dimension.equals(unit.getDimension())) .collect(Collectors.toSet()); } - - @SuppressWarnings("unchecked") - @Override - public > Unit getUnit(Class quantityType) { - return quantityToUnit.get(quantityType); - } - - protected static class Helper { + + @SuppressWarnings("unchecked") + @Override + public > Unit getUnit(Class quantityType) { + return quantityToUnit.get(quantityType); + } + + protected static class Helper { static Set> getUnitsOfDimension(final Set> units, Dimension dimension) { if (dimension != null) { return units.stream().filter(u -> dimension.equals(u.getDimension())).collect(Collectors.toSet()); @@ -123,158 +123,158 @@ static Set> getUnitsOfDimension(final Set> units, Dimension dime } return null; } - - /** - * Adds a new named unit to the collection. - * - * @param unit - * the unit being added. - * @param name - * the name of the unit. - * @return unit. - * @since 1.0 - */ - public static > U addUnit(Set> units, U unit, String name) { - return addUnit(units, unit, name, NAME); - } - - /** - * Adds a new named unit to the collection. - * - * @param unit - * the unit being added. - * @param name - * the name of the unit. - * @param name - * the symbol of the unit. - * @return unit. - * @since 1.0 - */ - @SuppressWarnings("unchecked") - public static > U addUnit(Set> units, U unit, String name, String symbol) { - if (name != null && symbol != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setName(name); - aUnit.setSymbol(symbol); - units.add(aUnit); - return (U) aUnit; - } - if (name != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setName(name); - units.add(aUnit); - return (U) aUnit; - } - units.add(unit); - return unit; - } - - /** - * Adds a new named unit to the collection. - * - * @param unit - * the unit being added. - * @param name - * the name of the unit. - * @param name - * the symbol of the unit. - * @param style - * style of the unit. - * @return unit. - * @since 1.0.1 - */ - @SuppressWarnings("unchecked") - public static > U addUnit(Set> units, U unit, final String name, final String symbol, UnitStyle style) { - switch (style) { - case NAME: - case SYMBOL: - case SYMBOL_AND_LABEL: - if (name != null && symbol != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setName(name); - if (SYMBOL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { - aUnit.setSymbol(symbol); - } - if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { - SimpleUnitFormat.getInstance().label(unit, symbol); - } - units.add(aUnit); - return (U) aUnit; - } - if (name != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setName(name); - units.add(aUnit); - return (U) aUnit; - } - break; - default: - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.FINEST, "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + symbol + "'."); - } - break; - } - if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { - SimpleUnitFormat.getInstance().label(unit, symbol); - } - units.add(unit); - return unit; - } - - /** - * Adds a new labeled unit to the set. - * - * @param units - * the set to add to. - * - * @param unit - * the unit being added. - * @param text - * the text for the unit. - * @param style - * style of the unit. - * @return unit. - * @since 1.0.1 - */ - @SuppressWarnings("unchecked") - public static > U addUnit(Set> units, U unit, String text, UnitStyle style) { - switch (style) { - case NAME: - if (text != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setName(text); - units.add(aUnit); - return (U) aUnit; - } - break; - case SYMBOL: - if (text != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setSymbol(text); - units.add(aUnit); - return (U) aUnit; - } - break; - case SYMBOL_AND_LABEL: - if (text != null && unit instanceof AbstractUnit) { - AbstractUnit aUnit = (AbstractUnit) unit; - aUnit.setSymbol(text); - units.add(aUnit); - SimpleUnitFormat.getInstance().label(aUnit, text); - return (U) aUnit; - } else { // label in any case, returning below - SimpleUnitFormat.getInstance().label(unit, text); - } - break; - case LABEL: - SimpleUnitFormat.getInstance().label(unit, text); - break; - default: - logger.log(Level.FINEST, "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + text + "'."); - break; - } - units.add(unit); - return unit; - } - } -} + + /** + * Adds a new named unit to the collection. + * + * @param unit + * the unit being added. + * @param name + * the name of the unit. + * @return unit. + * @since 1.0 + */ + public static > U addUnit(Set> units, U unit, String name) { + return addUnit(units, unit, name, NAME); + } + + /** + * Adds a new named unit to the collection. + * + * @param unit + * the unit being added. + * @param name + * the name of the unit. + * @param name + * the symbol of the unit. + * @return unit. + * @since 1.0 + */ + @SuppressWarnings("unchecked") + public static > U addUnit(Set> units, U unit, String name, String symbol) { + if (name != null && symbol != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setName(name); + aUnit.setSymbol(symbol); + units.add(aUnit); + return (U) aUnit; + } + if (name != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setName(name); + units.add(aUnit); + return (U) aUnit; + } + units.add(unit); + return unit; + } + + /** + * Adds a new named unit to the collection. + * + * @param unit + * the unit being added. + * @param name + * the name of the unit. + * @param name + * the symbol of the unit. + * @param style + * style of the unit. + * @return unit. + * @since 1.0.1 + */ + @SuppressWarnings("unchecked") + public static > U addUnit(Set> units, U unit, final String name, final String symbol, UnitStyle style) { + switch (style) { + case NAME: + case SYMBOL: + case SYMBOL_AND_LABEL: + if (name != null && symbol != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setName(name); + if (SYMBOL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { + aUnit.setSymbol(symbol); + } + if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { + SimpleUnitFormat.getInstance().label(unit, symbol); + } + units.add(aUnit); + return (U) aUnit; + } + if (name != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setName(name); + units.add(aUnit); + return (U) aUnit; + } + break; + default: + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + symbol + "'."); + } + break; + } + if (LABEL.equals(style) || SYMBOL_AND_LABEL.equals(style)) { + SimpleUnitFormat.getInstance().label(unit, symbol); + } + units.add(unit); + return unit; + } + + /** + * Adds a new labeled unit to the set. + * + * @param units + * the set to add to. + * + * @param unit + * the unit being added. + * @param text + * the text for the unit. + * @param style + * style of the unit. + * @return unit. + * @since 1.0.1 + */ + @SuppressWarnings("unchecked") + public static > U addUnit(Set> units, U unit, String text, UnitStyle style) { + switch (style) { + case NAME: + if (text != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setName(text); + units.add(aUnit); + return (U) aUnit; + } + break; + case SYMBOL: + if (text != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setSymbol(text); + units.add(aUnit); + return (U) aUnit; + } + break; + case SYMBOL_AND_LABEL: + if (text != null && unit instanceof AbstractUnit) { + AbstractUnit aUnit = (AbstractUnit) unit; + aUnit.setSymbol(text); + units.add(aUnit); + SimpleUnitFormat.getInstance().label(aUnit, text); + return (U) aUnit; + } else { // label in any case, returning below + SimpleUnitFormat.getInstance().label(unit, text); + } + break; + case LABEL: + SimpleUnitFormat.getInstance().label(unit, text); + break; + default: + logger.log(Level.FINEST, "Unknown style " + style + "; unit " + unit + " can't be rendered with '" + text + "'."); + break; + } + units.add(unit); + return unit; + } + } +} diff --git a/src/main/java/tec/uom/se/AbstractUnit.java b/src/main/java/tec/uom/se/AbstractUnit.java index 66e404c4..2753dd66 100644 --- a/src/main/java/tec/uom/se/AbstractUnit.java +++ b/src/main/java/tec/uom/se/AbstractUnit.java @@ -1,521 +1,521 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se; - -import tec.uom.se.format.SimpleUnitFormat; -import tec.uom.se.function.AddConverter; -import tec.uom.se.function.MultiplyConverter; -import tec.uom.se.function.RationalConverter; -import tec.uom.se.quantity.QuantityDimension; -import tec.uom.se.spi.DimensionalModel; -import tec.uom.se.unit.AlternateUnit; -import tec.uom.se.unit.AnnotatedUnit; -import tec.uom.se.unit.ProductUnit; -import tec.uom.se.unit.TransformedUnit; - -import javax.measure.*; -import javax.measure.quantity.Dimensionless; - -import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -/** - *

- * The class represents units founded on the seven SI base units for seven base quantities assumed to be mutually independent. - *

- * - *

- * For all physics units, unit conversions are symmetrical: u1.getConverterTo(u2).equals(u2.getConverterTo(u1).inverse()). Non-physical - * units (e.g. currency units) for which conversion is not symmetrical should have their own separate class hierarchy and are considered distinct - * (e.g. financial units), although they can always be combined with physics units (e.g. "€/Kg", "$/h"). - *

- * - * @see Wikipedia: International System of Units - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0.8, August 8, 2017 - * @since 1.0 - */ -public abstract class AbstractUnit> implements ComparableUnit { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se; + +import tec.uom.se.format.SimpleUnitFormat; +import tec.uom.se.function.AddConverter; +import tec.uom.se.function.MultiplyConverter; +import tec.uom.se.function.RationalConverter; +import tec.uom.se.quantity.QuantityDimension; +import tec.uom.se.spi.DimensionalModel; +import tec.uom.se.unit.AlternateUnit; +import tec.uom.se.unit.AnnotatedUnit; +import tec.uom.se.unit.ProductUnit; +import tec.uom.se.unit.TransformedUnit; + +import javax.measure.*; +import javax.measure.quantity.Dimensionless; + +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + *

+ * The class represents units founded on the seven SI base units for seven base quantities assumed to be mutually independent. + *

+ * + *

+ * For all physics units, unit conversions are symmetrical: u1.getConverterTo(u2).equals(u2.getConverterTo(u1).inverse()). Non-physical + * units (e.g. currency units) for which conversion is not symmetrical should have their own separate class hierarchy and are considered distinct + * (e.g. financial units), although they can always be combined with physics units (e.g. "€/Kg", "$/h"). + *

+ * + * @see Wikipedia: International System of Units + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0.8, August 8, 2017 + * @since 1.0 + */ +public abstract class AbstractUnit> implements ComparableUnit { + /** * - */ - private static final long serialVersionUID = -4344589505537030204L; - - /** - * Holds the dimensionless unit ONE. - * - * @see Wikipedia: Natural Units - Choosing constants to - * normalize - * @see Units of Dimension One - */ - public static final Unit ONE = new ProductUnit<>(); - - /** - * Holds the name. - */ - protected String name; - - /** - * Holds the symbol. - */ - private String symbol; - - /** - * Holds the unique symbols collection (base units or alternate units). - */ - protected static final Map> SYMBOL_TO_UNIT = new HashMap<>(); - - /** - * DefaultQuantityFactory constructor. - */ - protected AbstractUnit() { - } - - protected Type getActualType() { - ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass(); - return parameterizedType.getActualTypeArguments()[0].getClass().getGenericInterfaces()[0]; - } - - /** - * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units). - * - * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the - * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations - * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required. - * - * @return equals(toSystemUnit()) - */ - public boolean isSystemUnit() { - Unit si = this.toSystemUnit(); - return (this == si) || this.equals(si); - } - - /** - * Returns the unscaled {@link SI} unit from which this unit is derived. - * + */ + private static final long serialVersionUID = -4344589505537030204L; + + /** + * Holds the dimensionless unit ONE. + * + * @see Wikipedia: Natural Units - Choosing constants to + * normalize + * @see Units of Dimension One + */ + public static final Unit ONE = new ProductUnit<>(); + + /** + * Holds the name. + */ + protected String name; + + /** + * Holds the symbol. + */ + private String symbol; + + /** + * Holds the unique symbols collection (base units or alternate units). + */ + protected static final Map> SYMBOL_TO_UNIT = new HashMap<>(); + + /** + * DefaultQuantityFactory constructor. + */ + protected AbstractUnit() { + } + + protected Type getActualType() { + ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass(); + return parameterizedType.getActualTypeArguments()[0].getClass().getGenericInterfaces()[0]; + } + + /** + * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units). + * + * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the + * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations + * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required. + * + * @return equals(toSystemUnit()) + */ + public boolean isSystemUnit() { + Unit si = this.toSystemUnit(); + return (this == si) || this.equals(si); + } + + /** + * Returns the unscaled {@link SI} unit from which this unit is derived. + * * The SI unit can be be used to identify a quantity given the unit. For example: static boolean isAngularVelocity(AbstractUnit unit) { - * return unit.toSystemUnit().equals(RADIAN.divide(SECOND)); } assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. - * - * @return the unscaled metric unit from which this unit is derived. - */ - protected abstract Unit toSystemUnit(); - - /** - * Returns the converter from this unit to its unscaled {@link #toSysemUnit System Unit} unit. - * - * @return getConverterTo(this.toSystemUnit()) - * @see #toSI - */ - public abstract UnitConverter getSystemConverter(); - - /** - * Annotates the specified unit. Annotation does not change the unit semantic. Annotations are often written between curly braces behind units. For - * example: + * return unit.toSystemUnit().equals(RADIAN.divide(SECOND)); } assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. + * + * @return the unscaled metric unit from which this unit is derived. + */ + protected abstract Unit toSystemUnit(); + + /** + * Returns the converter from this unit to its unscaled {@link #toSysemUnit System Unit} unit. + * + * @return getConverterTo(this.toSystemUnit()) + * @see #toSI + */ + public abstract UnitConverter getSystemConverter(); + + /** + * Annotates the specified unit. Annotation does not change the unit semantic. Annotations are often written between curly braces behind units. For + * example: * AbstractUnit PERCENT_VOL = Units.PERCENT.annotate("vol"); // "%{vol}" AbstractUnit KG_TOTAL = - * Units.KILOGRAM.annotate("total"); // "kg{total}" AbstractUnit RED_BLOOD_CELLS = Units.ONE.annotate("RBC"); // "{RBC}" - * - * Note: Annotation of system units are not considered themselves as system units. - * - * @param annotation - * the unit annotation. - * @return the annotated unit. - */ - public AnnotatedUnit annotate(String annotation) { - return new AnnotatedUnit<>(this, annotation); - } - - /** - * Returns the abstract unit represented by the specified characters as per default format. - * - * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat} in subclasses of AbstractUnit. - * - *

+ * Units.KILOGRAM.annotate("total"); // "kg{total}" AbstractUnit RED_BLOOD_CELLS = Units.ONE.annotate("RBC"); // "{RBC}" + * + * Note: Annotation of system units are not considered themselves as system units. + * + * @param annotation + * the unit annotation. + * @return the annotated unit. + */ + public AnnotatedUnit annotate(String annotation) { + return new AnnotatedUnit<>(this, annotation); + } + + /** + * Returns the abstract unit represented by the specified characters as per default format. + * + * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat} in subclasses of AbstractUnit. + * + *

* Note: The standard format supports dimensionless units. AbstractUnit PERCENT = - * AbstractUnit.parse("100").inverse().asType(Dimensionless.class); - *

- * - * @param charSequence - * the character sequence to parse. - * @return SimpleUnitFormat.getInstance().parse(csq, new ParsePosition(0)) - * @throws ParserException - * if the specified character sequence cannot be correctly parsed (e.g. not UCUM compliant). - */ - public static Unit parse(CharSequence charSequence) { - return SimpleUnitFormat.getInstance().parse(charSequence); - } - - /** - * Returns the standard representation of this physics unit. The string produced for a given unit is always the same; it is not affected by the - * locale. It can be used as a canonical string representation for exchanging units, or as a key for a Hashtable, etc. - * - * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat} in subclasses of AbstractUnit. - * - * @return SimpleUnitFormat.getInstance().format(this) - */ - @Override - public String toString() { - return SimpleUnitFormat.getInstance().format(this); - } - - // /////////////////////////////////////////////////////// - // Implements org.unitsofmeasurement.Unit interface // - // /////////////////////////////////////////////////////// - - /** - * Returns the system unit (unscaled SI unit) from which this unit is derived. They can be be used to identify a quantity given the unit. For - * example:
+ * AbstractUnit.parse("100").inverse().asType(Dimensionless.class); + *

+ * + * @param charSequence + * the character sequence to parse. + * @return SimpleUnitFormat.getInstance().parse(csq, new ParsePosition(0)) + * @throws ParserException + * if the specified character sequence cannot be correctly parsed (e.g. not UCUM compliant). + */ + public static Unit parse(CharSequence charSequence) { + return SimpleUnitFormat.getInstance().parse(charSequence); + } + + /** + * Returns the standard representation of this physics unit. The string produced for a given unit is always the same; it is not affected by the + * locale. It can be used as a canonical string representation for exchanging units, or as a key for a Hashtable, etc. + * + * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat} in subclasses of AbstractUnit. + * + * @return SimpleUnitFormat.getInstance().format(this) + */ + @Override + public String toString() { + return SimpleUnitFormat.getInstance().format(this); + } + + // /////////////////////////////////////////////////////// + // Implements org.unitsofmeasurement.Unit interface // + // /////////////////////////////////////////////////////// + + /** + * Returns the system unit (unscaled SI unit) from which this unit is derived. They can be be used to identify a quantity given the unit. For + * example:
* static boolean isAngularVelocity(AbstractUnit unit) {
  return unit.getSystemUnit().equals(RADIAN.divide(SECOND));
} - *
assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true.
- * - * @return the unscaled metric unit from which this unit is derived. - */ - @Override - public final Unit getSystemUnit() { - return toSystemUnit(); - } - - /** - * Indicates if this unit is compatible with the unit specified. To be compatible both units must be physics units having the same fundamental - * dimension. - * - * @param that - * the other unit. - * @return true if this unit and that unit have equals fundamental dimension according to the current physics model; false - * otherwise. - */ - @Override - public final boolean isCompatible(Unit that) { - if ((this == that) || this.equals(that)) - return true; - if (!(that instanceof AbstractUnit)) - return false; - Dimension thisDimension = this.getDimension(); - Dimension thatDimension = that.getDimension(); - if (thisDimension.equals(thatDimension)) - return true; - DimensionalModel model = DimensionalModel.current(); // Use - // dimensional - // analysis - // model. - return model.getFundamentalDimension(thisDimension).equals(model.getFundamentalDimension(thatDimension)); - } - - public boolean isEquivalentOf(Unit that) { - if (this.compareTo(that) == 0) - return true; - return this.getConverterTo(that).equals(that.getConverterTo(this)); - } - - /** - * Casts this unit to a parameterized unit of specified nature or throw a ClassCastException if the dimension of the specified quantity and this - * unit's dimension do not match (regardless whether or not the dimensions are independent or not). - * - * @param type - * the quantity class identifying the nature of the unit. - * @throws ClassCastException - * if the dimension of this unit is different from the SI dimension of the specified type. - * @see Units#getUnit(Class) - */ - @SuppressWarnings("unchecked") - @Override - public final > AbstractUnit asType(Class type) { - Dimension typeDimension = QuantityDimension.of(type); - if ((typeDimension != null) && (!typeDimension.equals(this.getDimension()))) - throw new ClassCastException("The unit: " + this + " is not compatible with quantities of type " + type); - return (AbstractUnit) this; - } - - @Override - public abstract Map, Integer> getBaseUnits(); - - @Override - public abstract Dimension getDimension(); - - protected void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public String getSymbol() { - return symbol; - } - - protected void setSymbol(String s) { - this.symbol = s; - } - - @Override - public final UnitConverter getConverterTo(Unit that) throws UnconvertibleException { - if ((this == that) || this.equals(that)) - return AbstractConverter.IDENTITY; // Shortcut. - Unit thisSystemUnit = this.getSystemUnit(); - Unit thatSystemUnit = that.getSystemUnit(); - if (!thisSystemUnit.equals(thatSystemUnit)) - try { - return getConverterToAny(that); - } catch (IncommensurableException e) { - throw new UnconvertibleException(e); - } - UnitConverter thisToSI = this.getSystemConverter(); - UnitConverter thatToSI = that.getConverterTo(thatSystemUnit); - return thatToSI.inverse().concatenate(thisToSI); - } - - @SuppressWarnings("rawtypes") - @Override - public final UnitConverter getConverterToAny(Unit that) throws IncommensurableException, UnconvertibleException { - if (!isCompatible(that)) - throw new IncommensurableException(this + " is not compatible with " + that); - AbstractUnit thatAbstr = (AbstractUnit) that; // Since both units are - // compatible they must - // be both physics - // units. - DimensionalModel model = DimensionalModel.current(); - Unit thisSystemUnit = this.getSystemUnit(); - UnitConverter thisToDimension = model.getDimensionalTransform(thisSystemUnit.getDimension()).concatenate(this.getSystemConverter()); - Unit thatSystemUnit = thatAbstr.getSystemUnit(); - UnitConverter thatToDimension = model.getDimensionalTransform(thatSystemUnit.getDimension()).concatenate(thatAbstr.getSystemConverter()); - return thatToDimension.inverse().concatenate(thisToDimension); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public final Unit alternate(String symbol) { - return new AlternateUnit(this, symbol); - } - - @Override - public final Unit transform(UnitConverter operation) { - Unit systemUnit = this.getSystemUnit(); - UnitConverter cvtr; - if (this.isSystemUnit()) { - cvtr = this.getSystemConverter().concatenate(operation); - } else { - cvtr = operation; - } - if (cvtr.equals(AbstractConverter.IDENTITY)) { - return systemUnit; - } else { - return new TransformedUnit<>(null, this, systemUnit, cvtr); - } - } - - @Override - public final Unit shift(double offset) { - if (offset == 0) - return this; - return transform(new AddConverter(offset)); - } - - @Override - public final Unit multiply(double factor) { - if (factor == 1) - return this; - if (isLongValue(factor)) - return transform(new RationalConverter(BigInteger.valueOf((long) factor), BigInteger.ONE)); - return transform(new MultiplyConverter(factor)); - } - - private static boolean isLongValue(double value) { - return !((value < Long.MIN_VALUE) || (value > Long.MAX_VALUE)) && Math.floor(value) == value; - } - - /** - * Returns the product of this unit with the one specified. - * - *

- * Note: If the specified unit (that) is not a physical unit, then that.multiply(this) is returned. - *

- * - * @param that - * the unit multiplicand. - * @return this * that - */ - @Override - public final Unit multiply(Unit that) { - if (that instanceof AbstractUnit) - return multiply((AbstractUnit) that); - // return that.multiply(this); // Commutatif. - return ProductUnit.getProductInstance(this, that); - } - - /** - * Returns the product of this physical unit with the one specified. - * - * @param that - * the physical unit multiplicand. - * @return this * that - */ - protected final Unit multiply(AbstractUnit that) { - if (this.equals(ONE)) - return that; - if (that.equals(ONE)) - return this; - return ProductUnit.getProductInstance(this, that); - } - - /** - * Returns the inverse of this physical unit. - * - * @return 1 / this - */ - @Override - public final Unit inverse() { - if (this.equals(ONE)) - return this; - return ProductUnit.getQuotientInstance(ONE, this); - } - - /** - * Returns the result of dividing this unit by the specifified divisor. If the factor is an integer value, the division is exact. For example: - * - *
+   * 
assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. + * + * @return the unscaled metric unit from which this unit is derived. + */ + @Override + public final Unit getSystemUnit() { + return toSystemUnit(); + } + + /** + * Indicates if this unit is compatible with the unit specified. To be compatible both units must be physics units having the same fundamental + * dimension. + * + * @param that + * the other unit. + * @return true if this unit and that unit have equals fundamental dimension according to the current physics model; false + * otherwise. + */ + @Override + public final boolean isCompatible(Unit that) { + if ((this == that) || this.equals(that)) + return true; + if (!(that instanceof AbstractUnit)) + return false; + Dimension thisDimension = this.getDimension(); + Dimension thatDimension = that.getDimension(); + if (thisDimension.equals(thatDimension)) + return true; + DimensionalModel model = DimensionalModel.current(); // Use + // dimensional + // analysis + // model. + return model.getFundamentalDimension(thisDimension).equals(model.getFundamentalDimension(thatDimension)); + } + + public boolean isEquivalentOf(Unit that) { + if (this.compareTo(that) == 0) + return true; + return this.getConverterTo(that).equals(that.getConverterTo(this)); + } + + /** + * Casts this unit to a parameterized unit of specified nature or throw a ClassCastException if the dimension of the specified quantity and this + * unit's dimension do not match (regardless whether or not the dimensions are independent or not). + * + * @param type + * the quantity class identifying the nature of the unit. + * @throws ClassCastException + * if the dimension of this unit is different from the SI dimension of the specified type. + * @see Units#getUnit(Class) + */ + @SuppressWarnings("unchecked") + @Override + public final > AbstractUnit asType(Class type) { + Dimension typeDimension = QuantityDimension.of(type); + if ((typeDimension != null) && (!typeDimension.equals(this.getDimension()))) + throw new ClassCastException("The unit: " + this + " is not compatible with quantities of type " + type); + return (AbstractUnit) this; + } + + @Override + public abstract Map, Integer> getBaseUnits(); + + @Override + public abstract Dimension getDimension(); + + protected void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getSymbol() { + return symbol; + } + + protected void setSymbol(String s) { + this.symbol = s; + } + + @Override + public final UnitConverter getConverterTo(Unit that) throws UnconvertibleException { + if ((this == that) || this.equals(that)) + return AbstractConverter.IDENTITY; // Shortcut. + Unit thisSystemUnit = this.getSystemUnit(); + Unit thatSystemUnit = that.getSystemUnit(); + if (!thisSystemUnit.equals(thatSystemUnit)) + try { + return getConverterToAny(that); + } catch (IncommensurableException e) { + throw new UnconvertibleException(e); + } + UnitConverter thisToSI = this.getSystemConverter(); + UnitConverter thatToSI = that.getConverterTo(thatSystemUnit); + return thatToSI.inverse().concatenate(thisToSI); + } + + @SuppressWarnings("rawtypes") + @Override + public final UnitConverter getConverterToAny(Unit that) throws IncommensurableException, UnconvertibleException { + if (!isCompatible(that)) + throw new IncommensurableException(this + " is not compatible with " + that); + AbstractUnit thatAbstr = (AbstractUnit) that; // Since both units are + // compatible they must + // be both physics + // units. + DimensionalModel model = DimensionalModel.current(); + Unit thisSystemUnit = this.getSystemUnit(); + UnitConverter thisToDimension = model.getDimensionalTransform(thisSystemUnit.getDimension()).concatenate(this.getSystemConverter()); + Unit thatSystemUnit = thatAbstr.getSystemUnit(); + UnitConverter thatToDimension = model.getDimensionalTransform(thatSystemUnit.getDimension()).concatenate(thatAbstr.getSystemConverter()); + return thatToDimension.inverse().concatenate(thisToDimension); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public final Unit alternate(String symbol) { + return new AlternateUnit(this, symbol); + } + + @Override + public final Unit transform(UnitConverter operation) { + Unit systemUnit = this.getSystemUnit(); + UnitConverter cvtr; + if (this.isSystemUnit()) { + cvtr = this.getSystemConverter().concatenate(operation); + } else { + cvtr = operation; + } + if (cvtr.equals(AbstractConverter.IDENTITY)) { + return systemUnit; + } else { + return new TransformedUnit<>(null, this, systemUnit, cvtr); + } + } + + @Override + public final Unit shift(double offset) { + if (offset == 0) + return this; + return transform(new AddConverter(offset)); + } + + @Override + public final Unit multiply(double factor) { + if (factor == 1) + return this; + if (isLongValue(factor)) + return transform(new RationalConverter(BigInteger.valueOf((long) factor), BigInteger.ONE)); + return transform(new MultiplyConverter(factor)); + } + + private static boolean isLongValue(double value) { + return !((value < Long.MIN_VALUE) || (value > Long.MAX_VALUE)) && Math.floor(value) == value; + } + + /** + * Returns the product of this unit with the one specified. + * + *

+ * Note: If the specified unit (that) is not a physical unit, then that.multiply(this) is returned. + *

+ * + * @param that + * the unit multiplicand. + * @return this * that + */ + @Override + public final Unit multiply(Unit that) { + if (that instanceof AbstractUnit) + return multiply((AbstractUnit) that); + // return that.multiply(this); // Commutatif. + return ProductUnit.getProductInstance(this, that); + } + + /** + * Returns the product of this physical unit with the one specified. + * + * @param that + * the physical unit multiplicand. + * @return this * that + */ + protected final Unit multiply(AbstractUnit that) { + if (this.equals(ONE)) + return that; + if (that.equals(ONE)) + return this; + return ProductUnit.getProductInstance(this, that); + } + + /** + * Returns the inverse of this physical unit. + * + * @return 1 / this + */ + @Override + public final Unit inverse() { + if (this.equals(ONE)) + return this; + return ProductUnit.getQuotientInstance(ONE, this); + } + + /** + * Returns the result of dividing this unit by the specifified divisor. If the factor is an integer value, the division is exact. For example: + * + *
    * 
    *    QUART = GALLON_LIQUID_US.divide(4); // Exact definition.
-   * 
-   * 
- * - * @param divisor - * the divisor value. - * @return this unit divided by the specified divisor. - */ - @Override - public final Unit divide(double divisor) { - if (divisor == 1) - return this; - if (isLongValue(divisor)) - return transform(new RationalConverter(BigInteger.ONE, BigInteger.valueOf((long) divisor))); - return transform(new MultiplyConverter(1.0 / divisor)); - } - - /** - * Returns the quotient of this unit with the one specified. - * - * @param that - * the unit divisor. - * @return this.multiply(that.inverse()) - */ - @Override - public final Unit divide(Unit that) { - return this.multiply(that.inverse()); - } - - /** - * Returns the quotient of this physical unit with the one specified. - * - * @param that - * the physical unit divisor. - * @return this.multiply(that.inverse()) - */ - protected final Unit divide(AbstractUnit that) { - return this.multiply(that.inverse()); - } - - /** - * Returns a unit equals to the given root of this unit. - * - * @param n - * the root's order. - * @return the result of taking the given root of this unit. - * @throws ArithmeticException - * if n == 0 or if this operation would result in an unit with a fractional exponent. - */ - @Override - public final Unit root(int n) { - if (n > 0) - return ProductUnit.getRootInstance(this, n); - else if (n == 0) - throw new ArithmeticException("Root's order of zero"); - else - // n < 0 - return ONE.divide(this.root(-n)); - } - - /** - * Returns a unit equals to this unit raised to an exponent. - * - * @param n - * the exponent. - * @return the result of raising this unit to the exponent. - */ - @Override - public final Unit pow(int n) { - if (n > 0) - return this.multiply(this.pow(n - 1)); - else if (n == 0) - return ONE; - else - // n < 0 - return ONE.divide(this.pow(-n)); - } - - /** - * Compares this unit to the specified unit. The default implementation compares the name and symbol of both this unit and the specified unit. - * - * @return a negative integer, zero, or a positive integer as this unit is less than, equal to, or greater than the specified unit. - */ - public int compareTo(Unit that) { - if (name != null && getSymbol() != null) { - return name.compareTo(that.getName()) + getSymbol().compareTo(that.getSymbol()); - } else if (name == null) { - if (getSymbol() != null && that.getSymbol() != null) { - return getSymbol().compareTo(that.getSymbol()); - } else { - return -1; - } - } else if (getSymbol() == null) { - if (name != null) { - return name.compareTo(that.getName()); - } else { - return -1; - } - } else { - return -1; - } - } - - // ////////////////////////////////////////////////////////////// - // Ensures that sub-classes implements hashCode/equals method. - // ////////////////////////////////////////////////////////////// - - @Override - public abstract int hashCode(); - - @Override - public abstract boolean equals(Object that); -} + * + *
+ * + * @param divisor + * the divisor value. + * @return this unit divided by the specified divisor. + */ + @Override + public final Unit divide(double divisor) { + if (divisor == 1) + return this; + if (isLongValue(divisor)) + return transform(new RationalConverter(BigInteger.ONE, BigInteger.valueOf((long) divisor))); + return transform(new MultiplyConverter(1.0 / divisor)); + } + + /** + * Returns the quotient of this unit with the one specified. + * + * @param that + * the unit divisor. + * @return this.multiply(that.inverse()) + */ + @Override + public final Unit divide(Unit that) { + return this.multiply(that.inverse()); + } + + /** + * Returns the quotient of this physical unit with the one specified. + * + * @param that + * the physical unit divisor. + * @return this.multiply(that.inverse()) + */ + protected final Unit divide(AbstractUnit that) { + return this.multiply(that.inverse()); + } + + /** + * Returns a unit equals to the given root of this unit. + * + * @param n + * the root's order. + * @return the result of taking the given root of this unit. + * @throws ArithmeticException + * if n == 0 or if this operation would result in an unit with a fractional exponent. + */ + @Override + public final Unit root(int n) { + if (n > 0) + return ProductUnit.getRootInstance(this, n); + else if (n == 0) + throw new ArithmeticException("Root's order of zero"); + else + // n < 0 + return ONE.divide(this.root(-n)); + } + + /** + * Returns a unit equals to this unit raised to an exponent. + * + * @param n + * the exponent. + * @return the result of raising this unit to the exponent. + */ + @Override + public final Unit pow(int n) { + if (n > 0) + return this.multiply(this.pow(n - 1)); + else if (n == 0) + return ONE; + else + // n < 0 + return ONE.divide(this.pow(-n)); + } + + /** + * Compares this unit to the specified unit. The default implementation compares the name and symbol of both this unit and the specified unit. + * + * @return a negative integer, zero, or a positive integer as this unit is less than, equal to, or greater than the specified unit. + */ + public int compareTo(Unit that) { + if (name != null && getSymbol() != null) { + return name.compareTo(that.getName()) + getSymbol().compareTo(that.getSymbol()); + } else if (name == null) { + if (getSymbol() != null && that.getSymbol() != null) { + return getSymbol().compareTo(that.getSymbol()); + } else { + return -1; + } + } else if (getSymbol() == null) { + if (name != null) { + return name.compareTo(that.getName()); + } else { + return -1; + } + } else { + return -1; + } + } + + // ////////////////////////////////////////////////////////////// + // Ensures that sub-classes implements hashCode/equals method. + // ////////////////////////////////////////////////////////////// + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object that); +} diff --git a/src/main/java/tec/uom/se/ComparableQuantity.java b/src/main/java/tec/uom/se/ComparableQuantity.java index fc46a43c..d310f039 100644 --- a/src/main/java/tec/uom/se/ComparableQuantity.java +++ b/src/main/java/tec/uom/se/ComparableQuantity.java @@ -1,192 +1,192 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se; - -import java.io.Serializable; - -import javax.measure.Quantity; -import javax.measure.Unit; - -/** - * Quantity specialized for the Java SE platform. It extends {@link Quantity} with {@linkplain Comparable} and {@linkplain Serializable } - * - * @see {@link Quantity} - * @author otaviojava - * @author werner - * @param - * @since 1.0 - */ -public interface ComparableQuantity> extends Quantity, Comparable>, Serializable { - - /** - * @see Quantity#add(Quantity) - */ - ComparableQuantity add(Quantity that); - - /** - * @see Quantity#subtract(Quantity) - */ - ComparableQuantity subtract(Quantity that); - - /** - * @see Quantity#divide(Quantity) - */ - ComparableQuantity divide(Quantity that); - - /** - * @see Quantity#divide(Number) - */ - ComparableQuantity divide(Number that); - - /** - * @see Quantity#multiply(Quantity) - */ - ComparableQuantity multiply(Quantity multiplier); - - /** - * @see Quantity#multiply(Number) - */ - ComparableQuantity multiply(Number multiplier); - - /** - * @see Quantity#inverse() - */ - ComparableQuantity inverse(); - - /** - * invert and already cast to defined quantityClass - * - * @param quantityClass - * Quantity to be converted - * @see Quantity#inverse() - * @see Quantity#asType(Class) - */ - > ComparableQuantity inverse(Class quantityClass); - - /** - * @see Quantity#to(Unit) - */ - ComparableQuantity to(Unit unit); - - /** - * @see Quantity#asType(Class) - */ - > ComparableQuantity asType(Class type) throws ClassCastException; - - /** - * Compares two instances of {@link Quantity }. Conversion of unit can happen if necessary - * - * @param that - * the {@code quantity} to be compared with this instance. - * @return {@code true} if {@code that > this}. - * @throws NullPointerException - * if the that is null - */ - boolean isGreaterThan(Quantity that); - - /** - * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. - * - * @param that - * the {@code quantity} to be compared with this instance. - * @return {@code true} if {@code that >= this}. - * @throws NullPointerException - * if the that is null - */ - boolean isGreaterThanOrEqualTo(Quantity that); - - /** - * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. - * - * @param that - * the {@code quantity} to be compared with this instance. - * @return {@code true} if {@code that < this}. - * @throws NullPointerException - * if the quantity is null - */ - boolean isLessThan(Quantity that); - - /** - * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. - * - * @param that - * the {@code quantity} to be compared with this instance. - * @return {@code true} if {@code that < this}. - * @throws NullPointerException - * if the quantity is null - */ - boolean isLessThanOrEqualTo(Quantity that); - - /** - * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. - * - * @param that - * the {@code quantity} to be compared with this instance. - * @return {@code true} if {@code that < this}. - * @throws NullPointerException - * if the quantity is null - */ - boolean isEquivalentOf(Quantity that); - - /** - * @deprecated use #isEquivalentOf - */ - boolean isEquivalentTo(Quantity that); - - /** - * Multiply and cast the {@link ComparableQuantity} - * - * @param that - * quantity to be multiplied - * @param asTypeQuantity - * quantity to be converted - * @return the QuantityOperations multiplied and converted - * @see Quantity#divide(Quantity) - * @see Quantity#asType(Class) - * @exception NullPointerException - */ - , E extends Quantity> ComparableQuantity divide(Quantity that, Class asTypeQuantity); - - /** - * Divide and cast the {@link ComparableQuantity} - * - * @param that - * quantity to be divided - * @param asTypeQuantity - * quantity to be converted - * @return the QuantityOperations multiplied and converted - * @see QuantityOperations - * @see QuantityOperations#of(Quantity, Class) - * @see Quantity#asType(Class) - * @see Quantity#multiply(Quantity) - * @exception NullPointerException - */ - , E extends Quantity> ComparableQuantity multiply(Quantity that, Class asTypeQuantity); -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se; + +import java.io.Serializable; + +import javax.measure.Quantity; +import javax.measure.Unit; + +/** + * Quantity specialized for the Java SE platform. It extends {@link Quantity} with {@linkplain Comparable} and {@linkplain Serializable } + * + * @see {@link Quantity} + * @author otaviojava + * @author werner + * @param + * @since 1.0 + */ +public interface ComparableQuantity> extends Quantity, Comparable>, Serializable { + + /** + * @see Quantity#add(Quantity) + */ + ComparableQuantity add(Quantity that); + + /** + * @see Quantity#subtract(Quantity) + */ + ComparableQuantity subtract(Quantity that); + + /** + * @see Quantity#divide(Quantity) + */ + ComparableQuantity divide(Quantity that); + + /** + * @see Quantity#divide(Number) + */ + ComparableQuantity divide(Number that); + + /** + * @see Quantity#multiply(Quantity) + */ + ComparableQuantity multiply(Quantity multiplier); + + /** + * @see Quantity#multiply(Number) + */ + ComparableQuantity multiply(Number multiplier); + + /** + * @see Quantity#inverse() + */ + ComparableQuantity inverse(); + + /** + * invert and already cast to defined quantityClass + * + * @param quantityClass + * Quantity to be converted + * @see Quantity#inverse() + * @see Quantity#asType(Class) + */ + > ComparableQuantity inverse(Class quantityClass); + + /** + * @see Quantity#to(Unit) + */ + ComparableQuantity to(Unit unit); + + /** + * @see Quantity#asType(Class) + */ + > ComparableQuantity asType(Class type) throws ClassCastException; + + /** + * Compares two instances of {@link Quantity }. Conversion of unit can happen if necessary + * + * @param that + * the {@code quantity} to be compared with this instance. + * @return {@code true} if {@code that > this}. + * @throws NullPointerException + * if the that is null + */ + boolean isGreaterThan(Quantity that); + + /** + * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. + * + * @param that + * the {@code quantity} to be compared with this instance. + * @return {@code true} if {@code that >= this}. + * @throws NullPointerException + * if the that is null + */ + boolean isGreaterThanOrEqualTo(Quantity that); + + /** + * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. + * + * @param that + * the {@code quantity} to be compared with this instance. + * @return {@code true} if {@code that < this}. + * @throws NullPointerException + * if the quantity is null + */ + boolean isLessThan(Quantity that); + + /** + * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. + * + * @param that + * the {@code quantity} to be compared with this instance. + * @return {@code true} if {@code that < this}. + * @throws NullPointerException + * if the quantity is null + */ + boolean isLessThanOrEqualTo(Quantity that); + + /** + * Compares two instances of {@link Quantity }, doing the conversion of unit if necessary. + * + * @param that + * the {@code quantity} to be compared with this instance. + * @return {@code true} if {@code that < this}. + * @throws NullPointerException + * if the quantity is null + */ + boolean isEquivalentOf(Quantity that); + + /** + * @deprecated use #isEquivalentOf + */ + boolean isEquivalentTo(Quantity that); + + /** + * Multiply and cast the {@link ComparableQuantity} + * + * @param that + * quantity to be multiplied + * @param asTypeQuantity + * quantity to be converted + * @return the QuantityOperations multiplied and converted + * @see Quantity#divide(Quantity) + * @see Quantity#asType(Class) + * @exception NullPointerException + */ + , E extends Quantity> ComparableQuantity divide(Quantity that, Class asTypeQuantity); + + /** + * Divide and cast the {@link ComparableQuantity} + * + * @param that + * quantity to be divided + * @param asTypeQuantity + * quantity to be converted + * @return the QuantityOperations multiplied and converted + * @see QuantityOperations + * @see QuantityOperations#of(Quantity, Class) + * @see Quantity#asType(Class) + * @see Quantity#multiply(Quantity) + * @exception NullPointerException + */ + , E extends Quantity> ComparableQuantity multiply(Quantity that, Class asTypeQuantity); +} diff --git a/src/main/java/tec/uom/se/ComparableUnit.java b/src/main/java/tec/uom/se/ComparableUnit.java index b05b6992..e647560e 100644 --- a/src/main/java/tec/uom/se/ComparableUnit.java +++ b/src/main/java/tec/uom/se/ComparableUnit.java @@ -1,68 +1,68 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se; - -import java.io.Serializable; - -import javax.measure.Quantity; -import javax.measure.Unit; - -/** - * Unit specialized for the Java SE platform. It extends {@link Unit} with {@linkplain Comparable} and {@linkplain Serializable } - * - * @see {@link Unit} - * @author werner - * @param - * @since 1.0.9 - */ -public interface ComparableUnit> extends Unit, Comparable>, Serializable { - - /** - * Compares two instances of {@link Unit }, doing the conversion of unit if necessary. - * - * @param that - * the {@code Unit} to be compared with this instance. - * @return {@code true} if {@code that < this}. - * @throws NullPointerException - * if the unit is null - */ - boolean isEquivalentOf(Unit that); - - /** - * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units). - * - * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the - * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations - * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required. - * - * @return equals(toSystemUnit()) - */ - boolean isSystemUnit(); -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se; + +import java.io.Serializable; + +import javax.measure.Quantity; +import javax.measure.Unit; + +/** + * Unit specialized for the Java SE platform. It extends {@link Unit} with {@linkplain Comparable} and {@linkplain Serializable } + * + * @see {@link Unit} + * @author werner + * @param + * @since 1.0.9 + */ +public interface ComparableUnit> extends Unit, Comparable>, Serializable { + + /** + * Compares two instances of {@link Unit }, doing the conversion of unit if necessary. + * + * @param that + * the {@code Unit} to be compared with this instance. + * @return {@code true} if {@code that < this}. + * @throws NullPointerException + * if the unit is null + */ + boolean isEquivalentOf(Unit that); + + /** + * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units). + * + * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the + * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations + * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required. + * + * @return equals(toSystemUnit()) + */ + boolean isSystemUnit(); +} diff --git a/src/main/java/tec/uom/se/format/AbstractUnitFormat.java b/src/main/java/tec/uom/se/format/AbstractUnitFormat.java index c1f42b7d..3aef8c48 100644 --- a/src/main/java/tec/uom/se/format/AbstractUnitFormat.java +++ b/src/main/java/tec/uom/se/format/AbstractUnitFormat.java @@ -1,156 +1,156 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import java.io.IOException; -import java.text.ParsePosition; - -import javax.measure.Unit; -import javax.measure.format.ParserException; -import javax.measure.format.UnitFormat; - -import tec.uom.se.AbstractUnit; - -/** - *

- * This class provides the interface for formatting and parsing {@link Unit units}. - *

- * - *

+/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import java.io.IOException; +import java.text.ParsePosition; + +import javax.measure.Unit; +import javax.measure.format.ParserException; +import javax.measure.format.UnitFormat; + +import tec.uom.se.AbstractUnit; + +/** + *

+ * This class provides the interface for formatting and parsing {@link Unit units}. + *

+ * + *

* For all metric units, the 20 SI prefixes used to form decimal multiples and sub-multiples of SI units are recognized. For example: * AbstractUnit.parse("m°C").equals(MetricPrefix.MILLI(Units.CELSIUS)) - * AbstractUnit.parse("kW").equals(MetricPrefix.KILO(Units.WATT)) - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0.2, $Date: 2017-02-25 $ - * @since 1.0 - * - */ -public abstract class AbstractUnitFormat implements UnitFormat { - - /** - * Returns the {@link SymbolMap} for this unit format. - * - * @return the symbol map used by this format. - */ - protected abstract SymbolMap getSymbols(); - - /** - * Formats the specified unit. - * - * @param unit - * the unit to format. - * @param appendable - * the appendable destination. - * @return The appendable destination passed in as {@code appendable}, with formatted text appended. - * @throws IOException - * if an error occurs. - */ - public abstract Appendable format(Unit unit, Appendable appendable) throws IOException; - - /** + * AbstractUnit.parse("kW").equals(MetricPrefix.KILO(Units.WATT)) + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0.2, $Date: 2017-02-25 $ + * @since 1.0 + * + */ +public abstract class AbstractUnitFormat implements UnitFormat { + + /** + * Returns the {@link SymbolMap} for this unit format. + * + * @return the symbol map used by this format. + */ + protected abstract SymbolMap getSymbols(); + + /** + * Formats the specified unit. + * + * @param unit + * the unit to format. + * @param appendable + * the appendable destination. + * @return The appendable destination passed in as {@code appendable}, with formatted text appended. + * @throws IOException + * if an error occurs. + */ + public abstract Appendable format(Unit unit, Appendable appendable) throws IOException; + + /** * Formats an object to produce a string. This is equivalent to
{@link #format(Unit, StringBuilder) format}(unit, - * new StringBuilder()).toString();
- * - * @param obj - * The object to format - * @return Formatted string. - * @exception IllegalArgumentException - * if the Format cannot format the given object - */ - public final String format(Unit unit) { - if (unit instanceof AbstractUnit) { - return format((AbstractUnit) unit, new StringBuilder()).toString(); - } else { - try { - return (this.format(unit, new StringBuilder())).toString(); - } catch (IOException ex) { - throw new ParserException(ex); // Should never happen. - } - } - } - - @Override - public void label(Unit unit, String label) { - // do nothing, if subclasses want to use it, override there - } - - /** - * Parses a portion of the specified CharSequence from the specified position to produce a unit. If there is no unit to parse - * {@link AbstractUnit#ONE} is returned. - * - * @param csq - * the CharSequence to parse. - * @param cursor - * the cursor holding the current parsing index. - * @return the unit parsed from the specified character sub-sequence. - * @throws IllegalArgumentException - * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). - */ - protected abstract Unit parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException; - - /** - * Parses a portion of the specified CharSequence from the specified position to produce a unit. If there is no unit to parse - * {@link AbstractUnit#ONE} is returned. - * - * @param csq - * the CharSequence to parse. - * @param index - * the current parsing index. - * @return the unit parsed from the specified character sub-sequence. - * @throws IllegalArgumentException - * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). - */ - protected abstract Unit parse(CharSequence csq, int index) throws IllegalArgumentException; - - /** - * Convenience method equivalent to {@link #format(AbstractUnit, Appendable)} except it does not raise an IOException. - * - * @param unit - * the unit to format. - * @param dest - * the appendable destination. - * @return the specified StringBuilder. - */ - final StringBuilder format(AbstractUnit unit, StringBuilder dest) { - try { - return (StringBuilder) this.format(unit, (Appendable) dest); - } catch (IOException ex) { - throw new Error(ex); // Can never happen. - } - } - - /** - * serialVersionUID - */ - // private static final long serialVersionUID = -2046025267890654321L; -} + * new StringBuilder()).toString(); + * + * @param obj + * The object to format + * @return Formatted string. + * @exception IllegalArgumentException + * if the Format cannot format the given object + */ + public final String format(Unit unit) { + if (unit instanceof AbstractUnit) { + return format((AbstractUnit) unit, new StringBuilder()).toString(); + } else { + try { + return (this.format(unit, new StringBuilder())).toString(); + } catch (IOException ex) { + throw new ParserException(ex); // Should never happen. + } + } + } + + @Override + public void label(Unit unit, String label) { + // do nothing, if subclasses want to use it, override there + } + + /** + * Parses a portion of the specified CharSequence from the specified position to produce a unit. If there is no unit to parse + * {@link AbstractUnit#ONE} is returned. + * + * @param csq + * the CharSequence to parse. + * @param cursor + * the cursor holding the current parsing index. + * @return the unit parsed from the specified character sub-sequence. + * @throws IllegalArgumentException + * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). + */ + protected abstract Unit parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException; + + /** + * Parses a portion of the specified CharSequence from the specified position to produce a unit. If there is no unit to parse + * {@link AbstractUnit#ONE} is returned. + * + * @param csq + * the CharSequence to parse. + * @param index + * the current parsing index. + * @return the unit parsed from the specified character sub-sequence. + * @throws IllegalArgumentException + * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). + */ + protected abstract Unit parse(CharSequence csq, int index) throws IllegalArgumentException; + + /** + * Convenience method equivalent to {@link #format(AbstractUnit, Appendable)} except it does not raise an IOException. + * + * @param unit + * the unit to format. + * @param dest + * the appendable destination. + * @return the specified StringBuilder. + */ + final StringBuilder format(AbstractUnit unit, StringBuilder dest) { + try { + return (StringBuilder) this.format(unit, (Appendable) dest); + } catch (IOException ex) { + throw new Error(ex); // Can never happen. + } + } + + /** + * serialVersionUID + */ + // private static final long serialVersionUID = -2046025267890654321L; +} diff --git a/src/main/java/tec/uom/se/format/ConverterFormatter.java b/src/main/java/tec/uom/se/format/ConverterFormatter.java index 21c7df8a..d46c45dd 100644 --- a/src/main/java/tec/uom/se/format/ConverterFormatter.java +++ b/src/main/java/tec/uom/se/format/ConverterFormatter.java @@ -1,225 +1,225 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import tec.uom.se.AbstractConverter; -import tec.uom.se.function.*; -import tec.uom.se.unit.MetricPrefix; - -import javax.measure.UnitConverter; -import java.math.BigInteger; -import java.util.Formattable; -import java.util.Formatter; - -import static java.lang.StrictMath.E; - -/** - * @author otaviojava - * @author keilw - */ -class ConverterFormatter { - - private static final String LOCAL_FORMAT_PATTERN = "%s"; - - /** - * Formats the given converter to the given StringBuilder and returns the operator precedence of the converter's mathematical operation. This is the - * default implementation, which supports all built-in UnitConverter implementations. Note that it recursively calls itself in the case of a - * {@link AbstractConverter.converter.UnitConverter.Compound Compound} converter. - * - * @param converter - * the converter to be formatted - * @param continued - * true if the converter expression should begin with an operator, otherwise false. - * @param unitPrecedence - * the operator precedence of the operation expressed by the unit being modified by the given converter. - * @param buffer - * the StringBuffer to append to. - * @return the operator precedence of the given UnitConverter - */ - static int formatConverter(UnitConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer, SymbolMap symbolMap) { - final MetricPrefix prefix = symbolMap.getPrefix((AbstractConverter) converter); - if ((prefix != null) && (unitPrecedence == EBNFHelper.NOOP_PRECEDENCE)) { - return noopPrecedence(buffer, symbolMap, prefix); - } else if (converter instanceof AddConverter) { - return additionPrecedence((AddConverter) converter, continued, unitPrecedence, buffer); - } else if (converter instanceof LogConverter) { - return exponentPrecedenceLogConveter((LogConverter) converter, buffer); - } else if (converter instanceof ExpConverter) { - return exponentPrecedenceExpConveter((ExpConverter) converter, unitPrecedence, buffer); - } else if (converter instanceof MultiplyConverter) { - return productPrecedence((MultiplyConverter) converter, continued, unitPrecedence, buffer); - } else if (converter instanceof RationalConverter) { - return productPrecedence((RationalConverter) converter, continued, unitPrecedence, buffer); - } else if (converter instanceof AbstractConverter.Pair) { - AbstractConverter.Pair compound = (AbstractConverter.Pair) converter; - if (compound.getLeft() == AbstractConverter.IDENTITY) { - return formatConverter(compound.getRight(), true, unitPrecedence, buffer, symbolMap); - } else { - if (compound.getLeft() instanceof Formattable) { - return formatFormattable((Formattable) compound.getLeft(), unitPrecedence, buffer); - } else if (compound.getRight() instanceof Formattable) { - return formatFormattable((Formattable) compound.getRight(), unitPrecedence, buffer); - } else { - return formatConverter(compound.getLeft(), true, unitPrecedence, buffer, symbolMap); - // FIXME use getRight() here, too - } - } - // return formatConverter(compound.getRight(), true, - // unitPrecedence, buffer); - - } else { - if (converter != null) { - // throw new IllegalArgumentException( - // "Unable to format the given UnitConverter: " + - // converter.getClass()); //$NON-NLS-1$ - buffer.replace(0, 1, converter.toString()); - return EBNFHelper.NOOP_PRECEDENCE; - } else - throw new IllegalArgumentException("Unable to format, no UnitConverter given"); //$NON-NLS-1$ - } - } - - private static int productPrecedence(RationalConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { - if (unitPrecedence < EBNFHelper.PRODUCT_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - RationalConverter rationalConverter = converter; - if (rationalConverter.getDividend() != BigInteger.ONE) { - if (continued) { - buffer.append(EBNFHelper.MIDDLE_DOT); - } - buffer.append(rationalConverter.getDividend()); - } - if (rationalConverter.getDivisor() != BigInteger.ONE) { - buffer.append('/'); - buffer.append(rationalConverter.getDivisor()); - } - return EBNFHelper.PRODUCT_PRECEDENCE; - } - - private static int productPrecedence(MultiplyConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { - if (unitPrecedence < EBNFHelper.PRODUCT_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - if (continued) { - buffer.append(EBNFHelper.MIDDLE_DOT); - } - double factor = converter.getFactor(); - long lFactor = (long) factor; - if (lFactor == factor) { - buffer.append(lFactor); - } else { - buffer.append(factor); - } - return EBNFHelper.PRODUCT_PRECEDENCE; - } - - private static int exponentPrecedenceExpConveter(ExpConverter converter, int unitPrecedence, StringBuilder buffer) { - if (unitPrecedence < EBNFHelper.EXPONENT_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - StringBuilder expr = new StringBuilder(); - double base = converter.getBase(); - if (base == E) { - expr.append('e'); - } else { - expr.append((int) base); - } - expr.append('^'); - buffer.insert(0, expr); - return EBNFHelper.EXPONENT_PRECEDENCE; - } - - private static int exponentPrecedenceLogConveter(LogConverter converter, StringBuilder buffer) { - double base = converter.getBase(); - StringBuilder expr = new StringBuilder(); - if (base == E) { - expr.append("ln"); //$NON-NLS-1$ - } else { - expr.append("log"); //$NON-NLS-1$ - if (base != 10) { - expr.append((int) base); - } - } - expr.append("("); //$NON-NLS-1$ - buffer.insert(0, expr); - buffer.append(")"); //$NON-NLS-1$ - return EBNFHelper.EXPONENT_PRECEDENCE; - } - - private static int additionPrecedence(AddConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { - if (unitPrecedence < EBNFHelper.ADDITION_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - double offset = converter.getOffset(); - if (offset < 0) { - buffer.append("-"); //$NON-NLS-1$ - offset = -offset; - } else if (continued) { - buffer.append("+"); //$NON-NLS-1$ - } - long lOffset = (long) offset; - if (lOffset == offset) { - buffer.append(lOffset); - } else { - buffer.append(offset); - } - return EBNFHelper.ADDITION_PRECEDENCE; - } - - private static int noopPrecedence(StringBuilder buffer, SymbolMap symbolMap, MetricPrefix prefix) { - buffer.insert(0, symbolMap.getSymbol(prefix)); - return EBNFHelper.NOOP_PRECEDENCE; - } - - /** - * Formats the given Formattable to the given StringBuffer and returns the given precedence of the converter's mathematical operation. - * - * @param f - * the formattable to be formatted - * @param unitPrecedence - * the operator precedence of the operation expressed by the unit being modified by the given converter. - * @param buffer - * the StringBuffer to append to. - * @return the given operator precedence - */ - private static int formatFormattable(Formattable f, int unitPrecedence, StringBuilder buffer) { - Formatter fmt = new Formatter(); - fmt.format(LOCAL_FORMAT_PATTERN, f); - buffer.replace(0, 1, fmt.toString()); - fmt.close(); // XXX try Java 7 with res, but for now let's leave J6 - // compliant - return unitPrecedence; - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import tec.uom.se.AbstractConverter; +import tec.uom.se.function.*; +import tec.uom.se.unit.MetricPrefix; + +import javax.measure.UnitConverter; +import java.math.BigInteger; +import java.util.Formattable; +import java.util.Formatter; + +import static java.lang.StrictMath.E; + +/** + * @author otaviojava + * @author keilw + */ +class ConverterFormatter { + + private static final String LOCAL_FORMAT_PATTERN = "%s"; + + /** + * Formats the given converter to the given StringBuilder and returns the operator precedence of the converter's mathematical operation. This is the + * default implementation, which supports all built-in UnitConverter implementations. Note that it recursively calls itself in the case of a + * {@link AbstractConverter.converter.UnitConverter.Compound Compound} converter. + * + * @param converter + * the converter to be formatted + * @param continued + * true if the converter expression should begin with an operator, otherwise false. + * @param unitPrecedence + * the operator precedence of the operation expressed by the unit being modified by the given converter. + * @param buffer + * the StringBuffer to append to. + * @return the operator precedence of the given UnitConverter + */ + static int formatConverter(UnitConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer, SymbolMap symbolMap) { + final MetricPrefix prefix = symbolMap.getPrefix((AbstractConverter) converter); + if ((prefix != null) && (unitPrecedence == EBNFHelper.NOOP_PRECEDENCE)) { + return noopPrecedence(buffer, symbolMap, prefix); + } else if (converter instanceof AddConverter) { + return additionPrecedence((AddConverter) converter, continued, unitPrecedence, buffer); + } else if (converter instanceof LogConverter) { + return exponentPrecedenceLogConveter((LogConverter) converter, buffer); + } else if (converter instanceof ExpConverter) { + return exponentPrecedenceExpConveter((ExpConverter) converter, unitPrecedence, buffer); + } else if (converter instanceof MultiplyConverter) { + return productPrecedence((MultiplyConverter) converter, continued, unitPrecedence, buffer); + } else if (converter instanceof RationalConverter) { + return productPrecedence((RationalConverter) converter, continued, unitPrecedence, buffer); + } else if (converter instanceof AbstractConverter.Pair) { + AbstractConverter.Pair compound = (AbstractConverter.Pair) converter; + if (compound.getLeft() == AbstractConverter.IDENTITY) { + return formatConverter(compound.getRight(), true, unitPrecedence, buffer, symbolMap); + } else { + if (compound.getLeft() instanceof Formattable) { + return formatFormattable((Formattable) compound.getLeft(), unitPrecedence, buffer); + } else if (compound.getRight() instanceof Formattable) { + return formatFormattable((Formattable) compound.getRight(), unitPrecedence, buffer); + } else { + return formatConverter(compound.getLeft(), true, unitPrecedence, buffer, symbolMap); + // FIXME use getRight() here, too + } + } + // return formatConverter(compound.getRight(), true, + // unitPrecedence, buffer); + + } else { + if (converter != null) { + // throw new IllegalArgumentException( + // "Unable to format the given UnitConverter: " + + // converter.getClass()); //$NON-NLS-1$ + buffer.replace(0, 1, converter.toString()); + return EBNFHelper.NOOP_PRECEDENCE; + } else + throw new IllegalArgumentException("Unable to format, no UnitConverter given"); //$NON-NLS-1$ + } + } + + private static int productPrecedence(RationalConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { + if (unitPrecedence < EBNFHelper.PRODUCT_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + RationalConverter rationalConverter = converter; + if (rationalConverter.getDividend() != BigInteger.ONE) { + if (continued) { + buffer.append(EBNFHelper.MIDDLE_DOT); + } + buffer.append(rationalConverter.getDividend()); + } + if (rationalConverter.getDivisor() != BigInteger.ONE) { + buffer.append('/'); + buffer.append(rationalConverter.getDivisor()); + } + return EBNFHelper.PRODUCT_PRECEDENCE; + } + + private static int productPrecedence(MultiplyConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { + if (unitPrecedence < EBNFHelper.PRODUCT_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + if (continued) { + buffer.append(EBNFHelper.MIDDLE_DOT); + } + double factor = converter.getFactor(); + long lFactor = (long) factor; + if (lFactor == factor) { + buffer.append(lFactor); + } else { + buffer.append(factor); + } + return EBNFHelper.PRODUCT_PRECEDENCE; + } + + private static int exponentPrecedenceExpConveter(ExpConverter converter, int unitPrecedence, StringBuilder buffer) { + if (unitPrecedence < EBNFHelper.EXPONENT_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + StringBuilder expr = new StringBuilder(); + double base = converter.getBase(); + if (base == E) { + expr.append('e'); + } else { + expr.append((int) base); + } + expr.append('^'); + buffer.insert(0, expr); + return EBNFHelper.EXPONENT_PRECEDENCE; + } + + private static int exponentPrecedenceLogConveter(LogConverter converter, StringBuilder buffer) { + double base = converter.getBase(); + StringBuilder expr = new StringBuilder(); + if (base == E) { + expr.append("ln"); //$NON-NLS-1$ + } else { + expr.append("log"); //$NON-NLS-1$ + if (base != 10) { + expr.append((int) base); + } + } + expr.append("("); //$NON-NLS-1$ + buffer.insert(0, expr); + buffer.append(")"); //$NON-NLS-1$ + return EBNFHelper.EXPONENT_PRECEDENCE; + } + + private static int additionPrecedence(AddConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { + if (unitPrecedence < EBNFHelper.ADDITION_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + double offset = converter.getOffset(); + if (offset < 0) { + buffer.append("-"); //$NON-NLS-1$ + offset = -offset; + } else if (continued) { + buffer.append("+"); //$NON-NLS-1$ + } + long lOffset = (long) offset; + if (lOffset == offset) { + buffer.append(lOffset); + } else { + buffer.append(offset); + } + return EBNFHelper.ADDITION_PRECEDENCE; + } + + private static int noopPrecedence(StringBuilder buffer, SymbolMap symbolMap, MetricPrefix prefix) { + buffer.insert(0, symbolMap.getSymbol(prefix)); + return EBNFHelper.NOOP_PRECEDENCE; + } + + /** + * Formats the given Formattable to the given StringBuffer and returns the given precedence of the converter's mathematical operation. + * + * @param f + * the formattable to be formatted + * @param unitPrecedence + * the operator precedence of the operation expressed by the unit being modified by the given converter. + * @param buffer + * the StringBuffer to append to. + * @return the given operator precedence + */ + private static int formatFormattable(Formattable f, int unitPrecedence, StringBuilder buffer) { + Formatter fmt = new Formatter(); + fmt.format(LOCAL_FORMAT_PATTERN, f); + buffer.replace(0, 1, fmt.toString()); + fmt.close(); // XXX try Java 7 with res, but for now let's leave J6 + // compliant + return unitPrecedence; + } +} diff --git a/src/main/java/tec/uom/se/format/DefaultQuantityFormat.java b/src/main/java/tec/uom/se/format/DefaultQuantityFormat.java index 0ce4c12c..e449ede0 100644 --- a/src/main/java/tec/uom/se/format/DefaultQuantityFormat.java +++ b/src/main/java/tec/uom/se/format/DefaultQuantityFormat.java @@ -1,107 +1,107 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import java.io.IOException; -import java.math.BigDecimal; -import java.text.ParsePosition; - -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.format.ParserException; - -import tec.uom.se.AbstractQuantity; -import tec.uom.se.AbstractUnit; -import tec.uom.se.ComparableQuantity; -import tec.uom.se.quantity.NumberQuantity; -import tec.uom.se.quantity.Quantities; - -/** - * Holds standard implementation - */ -@SuppressWarnings("rawtypes") -class DefaultQuantityFormat extends QuantityFormat { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import java.io.IOException; +import java.math.BigDecimal; +import java.text.ParsePosition; + +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.format.ParserException; + +import tec.uom.se.AbstractQuantity; +import tec.uom.se.AbstractUnit; +import tec.uom.se.ComparableQuantity; +import tec.uom.se.quantity.NumberQuantity; +import tec.uom.se.quantity.Quantities; + +/** + * Holds standard implementation + */ +@SuppressWarnings("rawtypes") +class DefaultQuantityFormat extends QuantityFormat { + /** * - */ - private static final long serialVersionUID = 2758248665095734058L; - - @Override - public Appendable format(Quantity measure, Appendable dest) throws IOException { - Unit unit = measure.getUnit(); - - dest.append(measure.getValue().toString()); - if (measure.getUnit().equals(AbstractUnit.ONE)) - return dest; - dest.append(' '); - return SimpleUnitFormat.getInstance().format(unit, dest); - } - - @SuppressWarnings("unchecked") - @Override - public ComparableQuantity parse(CharSequence csq, ParsePosition cursor) throws ParserException { - int startDecimal = cursor.getIndex(); - while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) { - startDecimal++; - } - int endDecimal = startDecimal + 1; - while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) { - endDecimal++; - } - BigDecimal decimal = new BigDecimal(csq.subSequence(startDecimal, endDecimal).toString()); - cursor.setIndex(endDecimal + 1); - Unit unit = SimpleUnitFormat.getInstance().parse(csq, cursor); - return Quantities.getQuantity(decimal, unit); - } - - @SuppressWarnings("unchecked") - @Override - AbstractQuantity parse(CharSequence csq, int index) throws ParserException { - int startDecimal = index; // cursor.getIndex(); - while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) { - startDecimal++; - } - int endDecimal = startDecimal + 1; - while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) { - endDecimal++; - } - Double decimal = new Double(csq.subSequence(startDecimal, endDecimal).toString()); - // cursor.setIndex(endDecimal + 1); - // Unit unit = EBNFUnitFormat.getInstance().parse(csq, index); - Unit unit = SimpleUnitFormat.getInstance().parse(csq, index); - return NumberQuantity.of(decimal, unit); - } - - @Override - public ComparableQuantity parse(CharSequence csq) throws ParserException { - return parse(csq, new ParsePosition(0)); - } + */ + private static final long serialVersionUID = 2758248665095734058L; + + @Override + public Appendable format(Quantity measure, Appendable dest) throws IOException { + Unit unit = measure.getUnit(); + + dest.append(measure.getValue().toString()); + if (measure.getUnit().equals(AbstractUnit.ONE)) + return dest; + dest.append(' '); + return SimpleUnitFormat.getInstance().format(unit, dest); + } + + @SuppressWarnings("unchecked") + @Override + public ComparableQuantity parse(CharSequence csq, ParsePosition cursor) throws ParserException { + int startDecimal = cursor.getIndex(); + while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) { + startDecimal++; + } + int endDecimal = startDecimal + 1; + while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) { + endDecimal++; + } + BigDecimal decimal = new BigDecimal(csq.subSequence(startDecimal, endDecimal).toString()); + cursor.setIndex(endDecimal + 1); + Unit unit = SimpleUnitFormat.getInstance().parse(csq, cursor); + return Quantities.getQuantity(decimal, unit); + } + + @SuppressWarnings("unchecked") + @Override + AbstractQuantity parse(CharSequence csq, int index) throws ParserException { + int startDecimal = index; // cursor.getIndex(); + while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) { + startDecimal++; + } + int endDecimal = startDecimal + 1; + while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) { + endDecimal++; + } + Double decimal = new Double(csq.subSequence(startDecimal, endDecimal).toString()); + // cursor.setIndex(endDecimal + 1); + // Unit unit = EBNFUnitFormat.getInstance().parse(csq, index); + Unit unit = SimpleUnitFormat.getInstance().parse(csq, index); + return NumberQuantity.of(decimal, unit); + } + + @Override + public ComparableQuantity parse(CharSequence csq) throws ParserException { + return parse(csq, new ParsePosition(0)); + } } \ No newline at end of file diff --git a/src/main/java/tec/uom/se/format/EBNFHelper.java b/src/main/java/tec/uom/se/format/EBNFHelper.java index 74afc8d0..85ebe4af 100644 --- a/src/main/java/tec/uom/se/format/EBNFHelper.java +++ b/src/main/java/tec/uom/se/format/EBNFHelper.java @@ -1,318 +1,318 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import static tec.uom.se.format.ConverterFormatter.formatConverter; -import tec.uom.se.AbstractUnit; -import tec.uom.se.unit.AnnotatedUnit; -import tec.uom.se.unit.BaseUnit; -import tec.uom.se.unit.TransformedUnit; - -import javax.measure.Unit; -import javax.measure.UnitConverter; - -import java.io.IOException; -import java.util.Map; - -import static tec.uom.se.unit.Units.*; - -/** - * Helper class that handles internals of formatting in {@link EBNFUnitFormat} - * - * @author otaviojava - * @author keilw - */ -class EBNFHelper { - - /** Operator precedence for the addition and subtraction operations */ - static final int ADDITION_PRECEDENCE = 0; - - /** Operator precedence for the multiplication and division operations */ - static final int PRODUCT_PRECEDENCE = ADDITION_PRECEDENCE + 2; - - /** Operator precedence for the exponentiation and logarithm operations */ - static final int EXPONENT_PRECEDENCE = PRODUCT_PRECEDENCE + 2; - - // private static final String LOCAL_FORMAT_PATTERN = "%s"; - - static final char MIDDLE_DOT = '\u00b7'; // $NON-NLS-1$ - - /** Exponent 1 character */ - private static final char EXPONENT_1 = '\u00b9'; // $NON-NLS-1$ - - /** Exponent 2 character */ - private static final char EXPONENT_2 = '\u00b2'; // $NON-NLS-1$ - - /** - * Operator precedence for a unit identifier containing no mathematical operations (i.e., consisting exclusively of an identifier and possibly a - * prefix). Defined to be Integer.MAX_VALUE so that no operator can have a higher precedence. - */ - static final int NOOP_PRECEDENCE = Integer.MAX_VALUE; - - /** - * Format the given unit to the given StringBuffer, then return the operator precedence of the outermost operator in the unit expression that was - * formatted. See {@link ConverterFormat} for the constants that define the various precedence values. - * - * @param unit - * the unit to be formatted - * @param buffer - * the StringBuffer to be written to - * @return the operator precedence of the outermost operator in the unit expression that was output - */ - static int formatInternal(Unit unit, Appendable buffer, SymbolMap symbolMap) throws IOException { - if (unit instanceof AnnotatedUnit) { - unit = ((AnnotatedUnit) unit).getActualUnit(); - // } else if (unit instanceof ProductUnit) { - // ProductUnit p = (ProductUnit)unit; - } - final String symbol = symbolMap.getSymbol(unit); - if (symbol != null) { - return noopPrecedenceInternal(buffer, symbol); - } else if (unit.getBaseUnits() != null) { - return productPrecedenceInternal(unit, buffer, symbolMap); - } else if (unit instanceof BaseUnit) { - return noopPrecedenceInternal(buffer, ((BaseUnit) unit).getSymbol()); - } else if (unit.getSymbol() != null) { // Alternate unit. - return noopPrecedenceInternal(buffer, unit.getSymbol()); - } else { // A transformed unit or new unit type! - // return newUnitPrecedenceInternal(unit, buffer, symbolMap); - // } - UnitConverter converter = null; - boolean printSeparator = false; - StringBuilder temp = new StringBuilder(); - int unitPrecedence = NOOP_PRECEDENCE; - Unit parentUnit = unit.getSystemUnit(); - converter = ((AbstractUnit) unit).getSystemConverter(); - if (KILOGRAM.equals(parentUnit)) { - // More special-case hackery to work around gram/kilogram - // incosistency - if (unit.equals(GRAM)) { - buffer.append(symbolMap.getSymbol(GRAM)); - return NOOP_PRECEDENCE; - } - parentUnit = GRAM; - if (unit instanceof TransformedUnit) { - converter = ((TransformedUnit) unit).getConverter(); - } else { - converter = unit.getConverterTo((Unit) GRAM); - } - } else if (CUBIC_METRE.equals(parentUnit)) { - if (converter != null) { - parentUnit = LITRE; - } - } - - if (unit instanceof TransformedUnit) { - TransformedUnit transUnit = (TransformedUnit) unit; - if (parentUnit == null) - parentUnit = transUnit.getSystemUnit(); - // parentUnit = transUnit.getParentUnit(); - // String x = parentUnit.toString(); - converter = transUnit.getConverter(); - } - - unitPrecedence = formatInternal(parentUnit, temp, symbolMap); - printSeparator = !parentUnit.equals(AbstractUnit.ONE); - int result = formatConverter(converter, printSeparator, unitPrecedence, temp, symbolMap); - buffer.append(temp); - return result; - } - } - - /** - * Format the given unit raised to the given fractional power to the given StringBuffer. - * - * @param unit - * Unit the unit to be formatted - * @param pow - * int the numerator of the fractional power - * @param root - * int the denominator of the fractional power - * @param continued - * boolean true if the converter expression should begin with an operator, otherwise false. This will always be - * true unless the unit being modified is equal to Unit.ONE. - * @param buffer - * StringBuffer the buffer to append to. No assumptions should be made about its content. - */ - private static void formatExponent(Unit unit, int pow, int root, boolean continued, Appendable buffer, SymbolMap symbolMap) throws IOException { - - if (continued) { - buffer.append(MIDDLE_DOT); - } - final StringBuilder temp = new StringBuilder(); - int unitPrecedence = EBNFHelper.formatInternal(unit, temp, symbolMap); - - if (unitPrecedence < EBNFHelper.PRODUCT_PRECEDENCE) { - temp.insert(0, '('); // $NON-NLS-1$ - temp.append(')'); // $NON-NLS-1$ - } - buffer.append(temp); - if ((root == 1) && (pow == 1)) { - // do nothing - } else if ((root == 1) && (pow > 1)) { - String powStr = Integer.toString(pow); - for (int i = 0; i < powStr.length(); i += 1) { - char c = powStr.charAt(i); - switch (c) { - case '0': - buffer.append('\u2070'); // $NON-NLS-1$ - break; - case '1': - buffer.append(EXPONENT_1); // $NON-NLS-1$ - break; - case '2': - buffer.append(EXPONENT_2); - break; - case '3': - buffer.append('\u00b3'); // $NON-NLS-1$ - break; - case '4': - buffer.append('\u2074'); // $NON-NLS-1$ - break; - case '5': - buffer.append('\u2075'); // $NON-NLS-1$ - break; - case '6': - buffer.append('\u2076'); // $NON-NLS-1$ - break; - case '7': - buffer.append('\u2077'); // $NON-NLS-1$ - break; - case '8': - buffer.append('\u2078'); // $NON-NLS-1$ - break; - case '9': - buffer.append('\u2079'); // $NON-NLS-1$ - break; - } - } - } else if (root == 1) { - buffer.append('^'); // $NON-NLS-1$ - buffer.append(String.valueOf(pow)); - } else { - buffer.append("^("); //$NON-NLS-1$ - buffer.append(String.valueOf(pow)); - buffer.append('/'); // $NON-NLS-1$ - buffer.append(String.valueOf(root)); - buffer.append(')'); // $NON-NLS-1$ - } - } - - private static int noopPrecedenceInternal(Appendable buffer, String symbol) throws IOException { - buffer.append(symbol); - return NOOP_PRECEDENCE; - } - - @SuppressWarnings("unchecked") - private static int productPrecedenceInternal(Unit unit, Appendable buffer, SymbolMap symbolMap) throws IOException { - Map, Integer> productUnits = (Map, Integer>) unit.getBaseUnits(); - int negativeExponentCount = 0; - // Write positive exponents first... - boolean start = true; - for (Map.Entry, Integer> e : productUnits.entrySet()) { - int pow = e.getValue(); - if (pow >= 0) { - formatExponent(e.getKey(), pow, 1, !start, buffer, symbolMap); - start = false; - } else { - negativeExponentCount += 1; - } - } - // ..then write negative exponents. - if (negativeExponentCount > 0) { - if (start) { - buffer.append('1'); - } - buffer.append('/'); - if (negativeExponentCount > 1) { - buffer.append('('); - } - start = true; - for (Map.Entry, Integer> e : productUnits.entrySet()) { - int pow = e.getValue(); - if (pow < 0) { - formatExponent(e.getKey(), -pow, 1, !start, buffer, symbolMap); - start = false; - } - } - if (negativeExponentCount > 1) { - buffer.append(')'); - } - } - return PRODUCT_PRECEDENCE; - } - - private static int newUnitPrecedenceInternal(Unit unit, Appendable buffer, SymbolMap symbolMap) throws IOException { - UnitConverter converter = null; - boolean printSeparator = false; - StringBuilder temp = new StringBuilder(); - int unitPrecedence = NOOP_PRECEDENCE; - Unit parentUnit = unit.getSystemUnit(); - converter = ((AbstractUnit) unit).getSystemConverter(); - if (KILOGRAM.equals(parentUnit)) { - if (unit instanceof TransformedUnit) { - // converter = ((TransformedUnit) unit).getConverter(); - - // More special-case hackery to work around gram/kilogram - // incosistency - if (unit.equals(GRAM)) { - return noopPrecedenceInternal(buffer, symbolMap.getSymbol(GRAM)); - } else { - // parentUnit = GRAM; - // converter = unit.getConverterTo((Unit) KILOGRAM); - converter = ((TransformedUnit) unit).getConverter(); - } - // parentUnit = GRAM; - } else { - converter = unit.getConverterTo((Unit) GRAM); - } - } else if (CUBIC_METRE.equals(parentUnit)) { - if (converter != null) { - parentUnit = LITRE; - } - } - - // TODO this may need to be in an else clause, could be related to - // https://github.com/unitsofmeasurement/si-units/issues/4 - if (unit instanceof TransformedUnit) { - TransformedUnit transUnit = (TransformedUnit) unit; - if (parentUnit == null) - parentUnit = transUnit.getParentUnit(); - // String x = parentUnit.toString(); - converter = transUnit.getConverter(); - } - - unitPrecedence = formatInternal(parentUnit, temp, symbolMap); - printSeparator = !parentUnit.equals(AbstractUnit.ONE); - int result = ConverterFormatter.formatConverter(converter, printSeparator, unitPrecedence, temp, symbolMap); - buffer.append(temp); - return result; - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import static tec.uom.se.format.ConverterFormatter.formatConverter; +import tec.uom.se.AbstractUnit; +import tec.uom.se.unit.AnnotatedUnit; +import tec.uom.se.unit.BaseUnit; +import tec.uom.se.unit.TransformedUnit; + +import javax.measure.Unit; +import javax.measure.UnitConverter; + +import java.io.IOException; +import java.util.Map; + +import static tec.uom.se.unit.Units.*; + +/** + * Helper class that handles internals of formatting in {@link EBNFUnitFormat} + * + * @author otaviojava + * @author keilw + */ +class EBNFHelper { + + /** Operator precedence for the addition and subtraction operations */ + static final int ADDITION_PRECEDENCE = 0; + + /** Operator precedence for the multiplication and division operations */ + static final int PRODUCT_PRECEDENCE = ADDITION_PRECEDENCE + 2; + + /** Operator precedence for the exponentiation and logarithm operations */ + static final int EXPONENT_PRECEDENCE = PRODUCT_PRECEDENCE + 2; + + // private static final String LOCAL_FORMAT_PATTERN = "%s"; + + static final char MIDDLE_DOT = '\u00b7'; // $NON-NLS-1$ + + /** Exponent 1 character */ + private static final char EXPONENT_1 = '\u00b9'; // $NON-NLS-1$ + + /** Exponent 2 character */ + private static final char EXPONENT_2 = '\u00b2'; // $NON-NLS-1$ + + /** + * Operator precedence for a unit identifier containing no mathematical operations (i.e., consisting exclusively of an identifier and possibly a + * prefix). Defined to be Integer.MAX_VALUE so that no operator can have a higher precedence. + */ + static final int NOOP_PRECEDENCE = Integer.MAX_VALUE; + + /** + * Format the given unit to the given StringBuffer, then return the operator precedence of the outermost operator in the unit expression that was + * formatted. See {@link ConverterFormat} for the constants that define the various precedence values. + * + * @param unit + * the unit to be formatted + * @param buffer + * the StringBuffer to be written to + * @return the operator precedence of the outermost operator in the unit expression that was output + */ + static int formatInternal(Unit unit, Appendable buffer, SymbolMap symbolMap) throws IOException { + if (unit instanceof AnnotatedUnit) { + unit = ((AnnotatedUnit) unit).getActualUnit(); + // } else if (unit instanceof ProductUnit) { + // ProductUnit p = (ProductUnit)unit; + } + final String symbol = symbolMap.getSymbol(unit); + if (symbol != null) { + return noopPrecedenceInternal(buffer, symbol); + } else if (unit.getBaseUnits() != null) { + return productPrecedenceInternal(unit, buffer, symbolMap); + } else if (unit instanceof BaseUnit) { + return noopPrecedenceInternal(buffer, ((BaseUnit) unit).getSymbol()); + } else if (unit.getSymbol() != null) { // Alternate unit. + return noopPrecedenceInternal(buffer, unit.getSymbol()); + } else { // A transformed unit or new unit type! + // return newUnitPrecedenceInternal(unit, buffer, symbolMap); + // } + UnitConverter converter = null; + boolean printSeparator = false; + StringBuilder temp = new StringBuilder(); + int unitPrecedence = NOOP_PRECEDENCE; + Unit parentUnit = unit.getSystemUnit(); + converter = ((AbstractUnit) unit).getSystemConverter(); + if (KILOGRAM.equals(parentUnit)) { + // More special-case hackery to work around gram/kilogram + // incosistency + if (unit.equals(GRAM)) { + buffer.append(symbolMap.getSymbol(GRAM)); + return NOOP_PRECEDENCE; + } + parentUnit = GRAM; + if (unit instanceof TransformedUnit) { + converter = ((TransformedUnit) unit).getConverter(); + } else { + converter = unit.getConverterTo((Unit) GRAM); + } + } else if (CUBIC_METRE.equals(parentUnit)) { + if (converter != null) { + parentUnit = LITRE; + } + } + + if (unit instanceof TransformedUnit) { + TransformedUnit transUnit = (TransformedUnit) unit; + if (parentUnit == null) + parentUnit = transUnit.getSystemUnit(); + // parentUnit = transUnit.getParentUnit(); + // String x = parentUnit.toString(); + converter = transUnit.getConverter(); + } + + unitPrecedence = formatInternal(parentUnit, temp, symbolMap); + printSeparator = !parentUnit.equals(AbstractUnit.ONE); + int result = formatConverter(converter, printSeparator, unitPrecedence, temp, symbolMap); + buffer.append(temp); + return result; + } + } + + /** + * Format the given unit raised to the given fractional power to the given StringBuffer. + * + * @param unit + * Unit the unit to be formatted + * @param pow + * int the numerator of the fractional power + * @param root + * int the denominator of the fractional power + * @param continued + * boolean true if the converter expression should begin with an operator, otherwise false. This will always be + * true unless the unit being modified is equal to Unit.ONE. + * @param buffer + * StringBuffer the buffer to append to. No assumptions should be made about its content. + */ + private static void formatExponent(Unit unit, int pow, int root, boolean continued, Appendable buffer, SymbolMap symbolMap) throws IOException { + + if (continued) { + buffer.append(MIDDLE_DOT); + } + final StringBuilder temp = new StringBuilder(); + int unitPrecedence = EBNFHelper.formatInternal(unit, temp, symbolMap); + + if (unitPrecedence < EBNFHelper.PRODUCT_PRECEDENCE) { + temp.insert(0, '('); // $NON-NLS-1$ + temp.append(')'); // $NON-NLS-1$ + } + buffer.append(temp); + if ((root == 1) && (pow == 1)) { + // do nothing + } else if ((root == 1) && (pow > 1)) { + String powStr = Integer.toString(pow); + for (int i = 0; i < powStr.length(); i += 1) { + char c = powStr.charAt(i); + switch (c) { + case '0': + buffer.append('\u2070'); // $NON-NLS-1$ + break; + case '1': + buffer.append(EXPONENT_1); // $NON-NLS-1$ + break; + case '2': + buffer.append(EXPONENT_2); + break; + case '3': + buffer.append('\u00b3'); // $NON-NLS-1$ + break; + case '4': + buffer.append('\u2074'); // $NON-NLS-1$ + break; + case '5': + buffer.append('\u2075'); // $NON-NLS-1$ + break; + case '6': + buffer.append('\u2076'); // $NON-NLS-1$ + break; + case '7': + buffer.append('\u2077'); // $NON-NLS-1$ + break; + case '8': + buffer.append('\u2078'); // $NON-NLS-1$ + break; + case '9': + buffer.append('\u2079'); // $NON-NLS-1$ + break; + } + } + } else if (root == 1) { + buffer.append('^'); // $NON-NLS-1$ + buffer.append(String.valueOf(pow)); + } else { + buffer.append("^("); //$NON-NLS-1$ + buffer.append(String.valueOf(pow)); + buffer.append('/'); // $NON-NLS-1$ + buffer.append(String.valueOf(root)); + buffer.append(')'); // $NON-NLS-1$ + } + } + + private static int noopPrecedenceInternal(Appendable buffer, String symbol) throws IOException { + buffer.append(symbol); + return NOOP_PRECEDENCE; + } + + @SuppressWarnings("unchecked") + private static int productPrecedenceInternal(Unit unit, Appendable buffer, SymbolMap symbolMap) throws IOException { + Map, Integer> productUnits = (Map, Integer>) unit.getBaseUnits(); + int negativeExponentCount = 0; + // Write positive exponents first... + boolean start = true; + for (Map.Entry, Integer> e : productUnits.entrySet()) { + int pow = e.getValue(); + if (pow >= 0) { + formatExponent(e.getKey(), pow, 1, !start, buffer, symbolMap); + start = false; + } else { + negativeExponentCount += 1; + } + } + // ..then write negative exponents. + if (negativeExponentCount > 0) { + if (start) { + buffer.append('1'); + } + buffer.append('/'); + if (negativeExponentCount > 1) { + buffer.append('('); + } + start = true; + for (Map.Entry, Integer> e : productUnits.entrySet()) { + int pow = e.getValue(); + if (pow < 0) { + formatExponent(e.getKey(), -pow, 1, !start, buffer, symbolMap); + start = false; + } + } + if (negativeExponentCount > 1) { + buffer.append(')'); + } + } + return PRODUCT_PRECEDENCE; + } + + private static int newUnitPrecedenceInternal(Unit unit, Appendable buffer, SymbolMap symbolMap) throws IOException { + UnitConverter converter = null; + boolean printSeparator = false; + StringBuilder temp = new StringBuilder(); + int unitPrecedence = NOOP_PRECEDENCE; + Unit parentUnit = unit.getSystemUnit(); + converter = ((AbstractUnit) unit).getSystemConverter(); + if (KILOGRAM.equals(parentUnit)) { + if (unit instanceof TransformedUnit) { + // converter = ((TransformedUnit) unit).getConverter(); + + // More special-case hackery to work around gram/kilogram + // incosistency + if (unit.equals(GRAM)) { + return noopPrecedenceInternal(buffer, symbolMap.getSymbol(GRAM)); + } else { + // parentUnit = GRAM; + // converter = unit.getConverterTo((Unit) KILOGRAM); + converter = ((TransformedUnit) unit).getConverter(); + } + // parentUnit = GRAM; + } else { + converter = unit.getConverterTo((Unit) GRAM); + } + } else if (CUBIC_METRE.equals(parentUnit)) { + if (converter != null) { + parentUnit = LITRE; + } + } + + // TODO this may need to be in an else clause, could be related to + // https://github.com/unitsofmeasurement/si-units/issues/4 + if (unit instanceof TransformedUnit) { + TransformedUnit transUnit = (TransformedUnit) unit; + if (parentUnit == null) + parentUnit = transUnit.getParentUnit(); + // String x = parentUnit.toString(); + converter = transUnit.getConverter(); + } + + unitPrecedence = formatInternal(parentUnit, temp, symbolMap); + printSeparator = !parentUnit.equals(AbstractUnit.ONE); + int result = ConverterFormatter.formatConverter(converter, printSeparator, unitPrecedence, temp, symbolMap); + buffer.append(temp); + return result; + } +} diff --git a/src/main/java/tec/uom/se/format/EBNFUnitFormat.java b/src/main/java/tec/uom/se/format/EBNFUnitFormat.java index e7e73894..eb184d47 100644 --- a/src/main/java/tec/uom/se/format/EBNFUnitFormat.java +++ b/src/main/java/tec/uom/se/format/EBNFUnitFormat.java @@ -1,285 +1,285 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import tec.uom.se.AbstractUnit; -import tec.uom.se.internal.format.TokenException; -import tec.uom.se.internal.format.TokenMgrError; -import tec.uom.se.internal.format.UnitFormatParser; -import tec.uom.se.unit.AnnotatedUnit; - -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.format.ParserException; - -import java.io.IOException; -import java.io.StringReader; -import java.text.ParsePosition; -import java.util.Locale; -import java.util.ResourceBundle; - -/** - *

- * This class represents the local neutral format. - *

- * - *

Here is the grammar for Units in Extended Backus-Naur Form (EBNF)

- *

- * Note that the grammar has been left-factored to be suitable for use by a top-down parser generator such as JavaCC - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Lexical Entities:
<sign>:="+" | "-"
<digit>:="0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<superscript_digit>:="⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"
<integer>:=(<digit>)+
<number>:=(<sign>)? (<digit>)* (".")? (<digit>)+ (("e" | "E") (<sign>)? (<digit>)+)?
<exponent>:=( "^" ( <sign> )? <integer> )
- * | ( "^(" (<sign>)? <integer> ( "/" (<sign>)? <integer> )? ")" )
- * | ( <superscript_digit> )+
<initial_char>:=? Any Unicode character excluding the following: ASCII control & whitespace (\u0000 - \u0020), decimal digits '0'-'9', '(' - * (\u0028), ')' (\u0029), '*' (\u002A), '+' (\u002B), '-' (\u002D), '.' (\u002E), '/' (\u005C), ':' (\u003A), '^' - * (\u005E), '²' (\u00B2), '³' (\u00B3), '·' (\u00B7), '¹' (\u00B9), '⁰' (\u2070), '⁴' (\u2074), '⁵' (\u2075), '⁶' - * (\u2076), '⁷' (\u2077), '⁸' (\u2078), '⁹' (\u2079) ?
<unit_identifier>:=<initial_char> ( <initial_char> | <digit> )*
Non-Terminals:
<unit_expr>:=<compound_expr>
<compound_expr>:=<add_expr> ( ":" <add_expr> )*
<add_expr>:=( <number> <sign> )? <mul_expr> ( <sign> <number> )?
<mul_expr>:=<exponent_expr> ( ( ( "*" | "·" ) <exponent_expr> ) | ( "/" <exponent_expr> ) )*
<exponent_expr>:=( <atomic_expr> ( <exponent> )? )
- * | (<integer> "^" <atomic_expr>)
- * | ( ( "log" ( <integer> )? ) | "ln" ) "(" <add_expr> ")" )
<atomic_expr>:=<number>
- * | <unit_identifier>
- * | ( "(" <add_expr> ")" )
- * - * @author Eric Russell - * @author Werner Keil - * @version 1.0.3, $Date: 2017-03-18 $ - * @since 1.0 - */ -public class EBNFUnitFormat extends AbstractUnitFormat { - - // //////////////////////////////////////////////////// - // Class variables // - // //////////////////////////////////////////////////// - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import tec.uom.se.AbstractUnit; +import tec.uom.se.internal.format.TokenException; +import tec.uom.se.internal.format.TokenMgrError; +import tec.uom.se.internal.format.UnitFormatParser; +import tec.uom.se.unit.AnnotatedUnit; + +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.format.ParserException; + +import java.io.IOException; +import java.io.StringReader; +import java.text.ParsePosition; +import java.util.Locale; +import java.util.ResourceBundle; + +/** + *

+ * This class represents the local neutral format. + *

+ * + *

Here is the grammar for Units in Extended Backus-Naur Form (EBNF)

+ *

+ * Note that the grammar has been left-factored to be suitable for use by a top-down parser generator such as JavaCC + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Lexical Entities:
<sign>:="+" | "-"
<digit>:="0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<superscript_digit>:="⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"
<integer>:=(<digit>)+
<number>:=(<sign>)? (<digit>)* (".")? (<digit>)+ (("e" | "E") (<sign>)? (<digit>)+)?
<exponent>:=( "^" ( <sign> )? <integer> )
+ * | ( "^(" (<sign>)? <integer> ( "/" (<sign>)? <integer> )? ")" )
+ * | ( <superscript_digit> )+
<initial_char>:=? Any Unicode character excluding the following: ASCII control & whitespace (\u0000 - \u0020), decimal digits '0'-'9', '(' + * (\u0028), ')' (\u0029), '*' (\u002A), '+' (\u002B), '-' (\u002D), '.' (\u002E), '/' (\u005C), ':' (\u003A), '^' + * (\u005E), '²' (\u00B2), '³' (\u00B3), '·' (\u00B7), '¹' (\u00B9), '⁰' (\u2070), '⁴' (\u2074), '⁵' (\u2075), '⁶' + * (\u2076), '⁷' (\u2077), '⁸' (\u2078), '⁹' (\u2079) ?
<unit_identifier>:=<initial_char> ( <initial_char> | <digit> )*
Non-Terminals:
<unit_expr>:=<compound_expr>
<compound_expr>:=<add_expr> ( ":" <add_expr> )*
<add_expr>:=( <number> <sign> )? <mul_expr> ( <sign> <number> )?
<mul_expr>:=<exponent_expr> ( ( ( "*" | "·" ) <exponent_expr> ) | ( "/" <exponent_expr> ) )*
<exponent_expr>:=( <atomic_expr> ( <exponent> )? )
+ * | (<integer> "^" <atomic_expr>)
+ * | ( ( "log" ( <integer> )? ) | "ln" ) "(" <add_expr> ")" )
<atomic_expr>:=<number>
+ * | <unit_identifier>
+ * | ( "(" <add_expr> ")" )
+ * + * @author Eric Russell + * @author Werner Keil + * @version 1.0.3, $Date: 2017-03-18 $ + * @since 1.0 + */ +public class EBNFUnitFormat extends AbstractUnitFormat { + + // //////////////////////////////////////////////////// + // Class variables // + // //////////////////////////////////////////////////// + /** * - */ - // private static final long serialVersionUID = 8968559300292910840L; - - /** - * Name of the resource bundle - */ - private static final String BUNDLE_NAME = "tec.uom.se.format.messages"; //$NON-NLS-1$ - - /** - * Default locale instance. If the default locale is changed after the class is initialized, this instance will no longer be used. - */ - private static final EBNFUnitFormat DEFAULT_INSTANCE = new EBNFUnitFormat(); - - /** - * Returns the instance for the current default locale (non-ascii characters are allowed) - */ - public static EBNFUnitFormat getInstance() { - return DEFAULT_INSTANCE; - } - - /** Returns an instance for the given symbol map. */ - public static EBNFUnitFormat getInstance(SymbolMap symbols) { - return new EBNFUnitFormat(symbols); - } - - // ////////////////////// - // Instance variables // - // ////////////////////// - /** - * The symbol map used by this instance to map between {@link org.unitsofmeasure.Unit Unit}s and Strings, etc... - */ - private final transient SymbolMap symbolMap; - - // //////////////// - // Constructors // - // //////////////// - /** - * Base constructor. - * - */ - EBNFUnitFormat() { - this(SymbolMap.of(ResourceBundle.getBundle(BUNDLE_NAME, Locale.ROOT))); - } - - /** - * Private constructor. - * - * @param symbols - * the symbol mapping. - */ - private EBNFUnitFormat(SymbolMap symbols) { - symbolMap = symbols; - } - - // ////////////////////// - // Instance methods // - // ////////////////////// - /** - * Get the symbol map used by this instance to map between {@link org.unitsofmeasure.Unit Unit}s and Strings, etc... - * - * @return SymbolMap the current symbol map - */ - protected SymbolMap getSymbols() { - return symbolMap; - } - - // ////////////// - // Formatting // - // ////////////// - public Appendable format(Unit unit, Appendable appendable) throws IOException { - - EBNFHelper.formatInternal(unit, appendable, symbolMap); - if (unit instanceof AnnotatedUnit) { - AnnotatedUnit annotatedUnit = (AnnotatedUnit) unit; - if (annotatedUnit.getAnnotation() != null) { - appendable.append('{'); - appendable.append(annotatedUnit.getAnnotation()); - appendable.append('}'); - } - } - return appendable; - } - - public boolean isLocaleSensitive() { - return false; - } - - @Override - protected Unit> parse(CharSequence csq, ParsePosition cursor) throws ParserException { - // Parsing reads the whole character sequence from the parse position. - int start = cursor != null ? cursor.getIndex() : 0; - int end = csq.length(); - if (end <= start) { - return AbstractUnit.ONE; - } - String source = csq.subSequence(start, end).toString().trim(); - if (source.length() == 0) { - return AbstractUnit.ONE; - } - try { - UnitFormatParser parser = new UnitFormatParser(symbolMap, new StringReader(source)); - Unit result = parser.parseUnit(); - if (cursor != null) - cursor.setIndex(end); - return result; - } catch (TokenException e) { - if (e.currentToken != null) { - cursor.setErrorIndex(start + e.currentToken.endColumn); - } else { - cursor.setErrorIndex(start); - } - throw new ParserException(e); - } catch (TokenMgrError e) { - cursor.setErrorIndex(start); - throw new IllegalArgumentException(e.getMessage()); - } - } - - @Override - protected Unit parse(CharSequence csq, int index) throws IllegalArgumentException { - return parse(csq, new ParsePosition(index)); - } - - public Unit parse(CharSequence csq) throws ParserException { - return parse(csq, 0); - } -} + */ + // private static final long serialVersionUID = 8968559300292910840L; + + /** + * Name of the resource bundle + */ + private static final String BUNDLE_NAME = "tec.uom.se.format.messages"; //$NON-NLS-1$ + + /** + * Default locale instance. If the default locale is changed after the class is initialized, this instance will no longer be used. + */ + private static final EBNFUnitFormat DEFAULT_INSTANCE = new EBNFUnitFormat(); + + /** + * Returns the instance for the current default locale (non-ascii characters are allowed) + */ + public static EBNFUnitFormat getInstance() { + return DEFAULT_INSTANCE; + } + + /** Returns an instance for the given symbol map. */ + public static EBNFUnitFormat getInstance(SymbolMap symbols) { + return new EBNFUnitFormat(symbols); + } + + // ////////////////////// + // Instance variables // + // ////////////////////// + /** + * The symbol map used by this instance to map between {@link org.unitsofmeasure.Unit Unit}s and Strings, etc... + */ + private final transient SymbolMap symbolMap; + + // //////////////// + // Constructors // + // //////////////// + /** + * Base constructor. + * + */ + EBNFUnitFormat() { + this(SymbolMap.of(ResourceBundle.getBundle(BUNDLE_NAME, Locale.ROOT))); + } + + /** + * Private constructor. + * + * @param symbols + * the symbol mapping. + */ + private EBNFUnitFormat(SymbolMap symbols) { + symbolMap = symbols; + } + + // ////////////////////// + // Instance methods // + // ////////////////////// + /** + * Get the symbol map used by this instance to map between {@link org.unitsofmeasure.Unit Unit}s and Strings, etc... + * + * @return SymbolMap the current symbol map + */ + protected SymbolMap getSymbols() { + return symbolMap; + } + + // ////////////// + // Formatting // + // ////////////// + public Appendable format(Unit unit, Appendable appendable) throws IOException { + + EBNFHelper.formatInternal(unit, appendable, symbolMap); + if (unit instanceof AnnotatedUnit) { + AnnotatedUnit annotatedUnit = (AnnotatedUnit) unit; + if (annotatedUnit.getAnnotation() != null) { + appendable.append('{'); + appendable.append(annotatedUnit.getAnnotation()); + appendable.append('}'); + } + } + return appendable; + } + + public boolean isLocaleSensitive() { + return false; + } + + @Override + protected Unit> parse(CharSequence csq, ParsePosition cursor) throws ParserException { + // Parsing reads the whole character sequence from the parse position. + int start = cursor != null ? cursor.getIndex() : 0; + int end = csq.length(); + if (end <= start) { + return AbstractUnit.ONE; + } + String source = csq.subSequence(start, end).toString().trim(); + if (source.length() == 0) { + return AbstractUnit.ONE; + } + try { + UnitFormatParser parser = new UnitFormatParser(symbolMap, new StringReader(source)); + Unit result = parser.parseUnit(); + if (cursor != null) + cursor.setIndex(end); + return result; + } catch (TokenException e) { + if (e.currentToken != null) { + cursor.setErrorIndex(start + e.currentToken.endColumn); + } else { + cursor.setErrorIndex(start); + } + throw new ParserException(e); + } catch (TokenMgrError e) { + cursor.setErrorIndex(start); + throw new IllegalArgumentException(e.getMessage()); + } + } + + @Override + protected Unit parse(CharSequence csq, int index) throws IllegalArgumentException { + return parse(csq, new ParsePosition(index)); + } + + public Unit parse(CharSequence csq) throws ParserException { + return parse(csq, 0); + } +} diff --git a/src/main/java/tec/uom/se/format/FormatBehavior.java b/src/main/java/tec/uom/se/format/FormatBehavior.java index 7fe5358f..635c8a14 100644 --- a/src/main/java/tec/uom/se/format/FormatBehavior.java +++ b/src/main/java/tec/uom/se/format/FormatBehavior.java @@ -1,53 +1,53 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -/** - * Defines different ways of formatting. - * - * @author Werner Keil - * @version 1.0 - * @since 1.0 - */ -public enum FormatBehavior { - - /** - * Formatting occurs in a locale-neutral way. - * - */ - LOCALE_NEUTRAL, - - /** - * Formatting occurs in a locale-sensitive way. - * - * @see java.util.Locale - */ - LOCALE_SENSITIVE +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +/** + * Defines different ways of formatting. + * + * @author Werner Keil + * @version 1.0 + * @since 1.0 + */ +public enum FormatBehavior { + + /** + * Formatting occurs in a locale-neutral way. + * + */ + LOCALE_NEUTRAL, + + /** + * Formatting occurs in a locale-sensitive way. + * + * @see java.util.Locale + */ + LOCALE_SENSITIVE } \ No newline at end of file diff --git a/src/main/java/tec/uom/se/format/LocalUnitFormat.java b/src/main/java/tec/uom/se/format/LocalUnitFormat.java index 811df323..5ef5a4ba 100644 --- a/src/main/java/tec/uom/se/format/LocalUnitFormat.java +++ b/src/main/java/tec/uom/se/format/LocalUnitFormat.java @@ -1,614 +1,614 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import static tec.uom.se.unit.Units.CUBIC_METRE; -import static tec.uom.se.unit.Units.GRAM; -import static tec.uom.se.unit.Units.KILOGRAM; -import static tec.uom.se.unit.Units.LITRE; -import tec.uom.se.AbstractUnit; -import tec.uom.se.function.AddConverter; -import tec.uom.se.function.MultiplyConverter; -import tec.uom.se.function.RationalConverter; -import tec.uom.se.internal.format.TokenException; -import tec.uom.se.internal.format.TokenMgrError; -import tec.uom.se.internal.format.LocalUnitFormatParser; -import tec.uom.se.unit.AlternateUnit; -import tec.uom.se.unit.AnnotatedUnit; -import tec.uom.se.unit.BaseUnit; -import tec.uom.se.unit.MetricPrefix; -import tec.uom.se.unit.TransformedUnit; -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.UnitConverter; -import javax.measure.format.ParserException; - -import java.io.IOException; -import java.io.StringReader; -import java.math.BigInteger; -import java.text.ParsePosition; -import java.util.Locale; -import java.util.Map; -import java.util.ResourceBundle; - -/** - *

- * This class represents the local sensitive format. - *

- * - *

Here is the grammar for CommonUnits in Extended Backus-Naur Form (EBNF)

- *

- * Note that the grammar has been left-factored to be suitable for use by a top-down parser generator such as JavaCC - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Lexical Entities:
<sign>:="+" | "-"
<digit>:="0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<superscript_digit>:="⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"
<integer>:=(<digit>)+
<number>:=(<sign>)? (<digit>)* (".")? (<digit>)+ (("e" | "E") (<sign>)? (<digit>)+)?
<exponent>:=( "^" ( <sign> )? <integer> )
- * | ( "^(" (<sign>)? <integer> ( "/" (<sign>)? <integer> )? ")" )
- * | ( <superscript_digit> )+
<initial_char>:=? Any Unicode character excluding the following: ASCII control & whitespace (\u0000 - \u0020), decimal digits '0'-'9', '(' - * (\u0028), ')' (\u0029), '*' (\u002A), '+' (\u002B), '-' (\u002D), '.' (\u002E), '/' (\u005C), ':' (\u003A), '^' - * (\u005E), '²' (\u00B2), '³' (\u00B3), '·' (\u00B7), '¹' (\u00B9), '⁰' (\u2070), '⁴' (\u2074), '⁵' (\u2075), '⁶' - * (\u2076), '⁷' (\u2077), '⁸' (\u2078), '⁹' (\u2079) ?
<unit_identifier>:=<initial_char> ( <initial_char> | <digit> )*
Non-Terminals:
<unit_expr>:=<compound_expr>
<compound_expr>:=<add_expr> ( ":" <add_expr> )*
<add_expr>:=( <number> <sign> )? <mul_expr> ( <sign> <number> )?
<mul_expr>:=<exponent_expr> ( ( ( "*" | "·" ) <exponent_expr> ) | ( "/" <exponent_expr> ) )*
<exponent_expr>:=( <atomic_expr> ( <exponent> )? )
- * | (<integer> "^" <atomic_expr>)
- * | ( ( "log" ( <integer> )? ) | "ln" ) "(" <add_expr> ")" )
<atomic_expr>:=<number>
- * | <unit_identifier>
- * | ( "(" <add_expr> ")" )
- * - * @author Eric Russell - * @author Werner Keil - * @version 1.0.2, April 30, 2017 - * @since 1.0 - */ -public class LocalUnitFormat extends AbstractUnitFormat { - - // //////////////////////////////////////////////////// - // Class variables // - // //////////////////////////////////////////////////// - /** - * DefaultQuantityFactory locale instance. If the default locale is changed after the class is initialized, this instance will no longer be used. - */ - private static final LocalUnitFormat DEFAULT_INSTANCE = new LocalUnitFormat(SymbolMap.of(ResourceBundle.getBundle(LocalUnitFormat.class - .getPackage().getName() + ".messages"))); - /** - * Multiplicand character - */ - private static final char MIDDLE_DOT = '\u00b7'; - /** - * Operator precedence for the addition and subtraction operations - */ - private static final int ADDITION_PRECEDENCE = 0; - /** - * Operator precedence for the multiplication and division operations - */ - private static final int PRODUCT_PRECEDENCE = ADDITION_PRECEDENCE + 2; - /** - * Operator precedence for the exponentiation and logarithm operations - */ - private static final int EXPONENT_PRECEDENCE = PRODUCT_PRECEDENCE + 2; - /** - * Operator precedence for a unit identifier containing no mathematical operations (i.e., consisting exclusively of an identifier and possibly a - * prefix). Defined to be Integer.MAX_VALUE so that no operator can have a higher precedence. - */ - private static final int NOOP_PRECEDENCE = Integer.MAX_VALUE; - - // ///////////////// - // Class methods // - // ///////////////// - /** - * Returns the instance for the current default locale (non-ascii characters are allowed) - */ - public static LocalUnitFormat getInstance() { - return DEFAULT_INSTANCE; - } - - /** - * Returns an instance for the given locale. - * - * @param locale - */ - public static LocalUnitFormat getInstance(Locale locale) { - return new LocalUnitFormat(SymbolMap.of(ResourceBundle.getBundle(LocalUnitFormat.class.getPackage().getName() + ".messages", locale))); - } - - /** Returns an instance for the given symbol map. */ - public static LocalUnitFormat getInstance(SymbolMap symbols) { - return new LocalUnitFormat(symbols); - } - - // ////////////////////// - // Instance variables // - // ////////////////////// - /** - * The symbol map used by this instance to map between {@link Unit Unit}s and Strings, etc... - */ - private final transient SymbolMap symbolMap; - - // //////////////// - // Constructors // - // //////////////// - /** - * Base constructor. - * - * @param symbols - * the symbol mapping. - */ - private LocalUnitFormat(SymbolMap symbols) { - symbolMap = symbols; - } - - // ////////////////////// - // Instance methods // - // ////////////////////// - /** - * Get the symbol map used by this instance to map between {@link AbstractUnit Unit}s and Strings, etc... - * - * @return SymbolMap the current symbol map - */ - @Override - protected SymbolMap getSymbols() { - return symbolMap; - } - - // ////////////// - // Formatting // - // ////////////// - @Override - public Appendable format(Unit unit, Appendable appendable) throws IOException { - if (!(unit instanceof AbstractUnit)) { - return appendable.append(unit.toString()); // Unknown unit (use - // intrinsic toString() - // method) - } - formatInternal(unit, appendable); - return appendable; - } - - public boolean isLocaleSensitive() { - return true; - } - - protected Unit parse(CharSequence csq, int index) throws ParserException { - return parse(csq, new ParsePosition(index)); - } - - public Unit parse(CharSequence csq, ParsePosition cursor) throws ParserException { - // Parsing reads the whole character sequence from the parse position. - int start = cursor.getIndex(); - int end = csq.length(); - if (end <= start) { - return AbstractUnit.ONE; - } - String source = csq.subSequence(start, end).toString().trim(); - if (source.length() == 0) { - return AbstractUnit.ONE; - } - try { - LocalUnitFormatParser parser = new LocalUnitFormatParser(symbolMap, new StringReader(source)); - Unit result = parser.parseUnit(); - cursor.setIndex(end); - return result; - } catch (TokenException e) { - if (e.currentToken != null) { - cursor.setErrorIndex(start + e.currentToken.endColumn); - } else { - cursor.setErrorIndex(start); - } - throw new IllegalArgumentException(e); // TODO should we throw - // ParserException here, - // too? - } catch (TokenMgrError e) { - cursor.setErrorIndex(start); - throw new ParserException(e); - } - } - - @Override - public Unit> parse(CharSequence csq) throws ParserException { - return parse(csq, new ParsePosition(0)); - } - - /** - * Format the given unit to the given StringBuilder, then return the operator precedence of the outermost operator in the unit expression that was - * formatted. See {@link ConverterFormat} for the constants that define the various precedence values. - * - * @param unit - * the unit to be formatted - * @param buffer - * the StringBuilder to be written to - * @return the operator precedence of the outermost operator in the unit expression that was output - */ - /* - * private int formatInternal(Unit unit, Appendable buffer) throws - * IOException { if (unit instanceof AnnotatedUnit) { unit = - * ((AnnotatedUnit) unit).getActualUnit(); } String symbol = - * symbolMap.getSymbol((AbstractUnit) unit); if (symbol != null) { - * buffer.append(symbol); return NOOP_PRECEDENCE; } else if - * (unit.getBaseUnits() != null) { Map productUnits - * = unit.getBaseUnits(); int negativeExponentCount = 0; // Write positive - * exponents first... boolean start = true; for (Unit u : - * productUnits.keySet()) { int pow = productUnits.get(u); if (pow >= 0) { - * formatExponent(u, pow, 1, !start, buffer); start = false; } else { - * negativeExponentCount += 1; } } // ..then write negative exponents. if - * (negativeExponentCount > 0) { if (start) { buffer.append('1'); } - * buffer.append('/'); if (negativeExponentCount > 1) { buffer.append('('); - * } start = true; for (Unit u : productUnits.keySet()) { int pow = - * productUnits.get(u); if (pow < 0) { formatExponent(u, -pow, 1, !start, - * buffer); start = false; } } if (negativeExponentCount > 1) { - * buffer.append(')'); } } return PRODUCT_PRECEDENCE; } else if - * ((!((AbstractUnit)unit).isSystemUnit()) || unit.equals(Units.KILOGRAM)) { - * UnitConverter converter = null; boolean printSeparator = false; - * StringBuffer temp = new StringBuffer(); int unitPrecedence = - * NOOP_PRECEDENCE; if (unit.equals(Units.KILOGRAM)) { // A special case - * because KILOGRAM is a BaseUnit instead of // a transformed unit, even - * though it has a prefix. converter = MetricPrefix.KILO.getConverter(); - * unitPrecedence = formatInternal(Units.GRAM, temp); printSeparator = true; - * } else { Unit parentUnit = unit.getSystemUnit(); converter = - * unit.getConverterTo(parentUnit); if (parentUnit.equals(Units.KILOGRAM)) { - * // More special-case hackery to work around gram/kilogram // incosistency - * parentUnit = Units.GRAM; converter = - * converter.concatenate(MetricPrefix.KILO.getConverter()); } unitPrecedence - * = formatInternal(parentUnit, temp); printSeparator = - * !parentUnit.equals(Units.ONE); } int result = formatConverter(converter, - * printSeparator, unitPrecedence, temp); buffer.append(temp); return - * result; } else if (unit.getSymbol() != null) { - * buffer.append(unit.getSymbol()); return NOOP_PRECEDENCE; } else { throw - * new IllegalArgumentException( - * "Cannot format the given Object as a Unit (unsupported unit type " + - * unit.getClass().getName() + ")"); } } - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private int formatInternal(Unit unit, Appendable buffer) throws IOException { - if (unit instanceof AnnotatedUnit) { - unit = ((AnnotatedUnit) unit).getActualUnit(); - // } else if (unit instanceof ProductUnit) { - // ProductUnit p = (ProductUnit)unit; - } - String symbol = symbolMap.getSymbol((AbstractUnit) unit); - if (symbol != null) { - buffer.append(symbol); - return NOOP_PRECEDENCE; - } else if (unit.getBaseUnits() != null) { - Map, Integer> productUnits = (Map, Integer>) unit.getBaseUnits(); - int negativeExponentCount = 0; - // Write positive exponents first... - boolean start = true; - for (Map.Entry, Integer> e : productUnits.entrySet()) { - int pow = e.getValue(); - if (pow >= 0) { - formatExponent(e.getKey(), pow, 1, !start, buffer); - start = false; - } else { - negativeExponentCount += 1; - } - } - // ..then write negative exponents. - if (negativeExponentCount > 0) { - if (start) { - buffer.append('1'); - } - buffer.append('/'); - if (negativeExponentCount > 1) { - buffer.append('('); - } - start = true; - for (Map.Entry, Integer> e : productUnits.entrySet()) { - int pow = e.getValue(); - if (pow < 0) { - formatExponent(e.getKey(), -pow, 1, !start, buffer); - start = false; - } - } - if (negativeExponentCount > 1) { - buffer.append(')'); - } - } - return PRODUCT_PRECEDENCE; - } else if (unit instanceof BaseUnit) { - buffer.append(((BaseUnit) unit).getSymbol()); - return NOOP_PRECEDENCE; - } else if (unit instanceof AlternateUnit) { // unit.getSymbol() != - // null) { // Alternate - // unit. - buffer.append(unit.getSymbol()); - return NOOP_PRECEDENCE; - } else { // A transformed unit or new unit type! - UnitConverter converter = null; - boolean printSeparator = false; - StringBuilder temp = new StringBuilder(); - int unitPrecedence = NOOP_PRECEDENCE; - Unit parentUnit = unit.getSystemUnit(); - converter = ((AbstractUnit) unit).getSystemConverter(); - if (KILOGRAM.equals(parentUnit)) { - // More special-case hackery to work around gram/kilogram - // incosistency - if (unit.equals(GRAM)) { - buffer.append(symbolMap.getSymbol(GRAM)); - return NOOP_PRECEDENCE; - } - parentUnit = GRAM; - if (unit instanceof TransformedUnit) { - converter = ((TransformedUnit) unit).getConverter(); - } else { - converter = unit.getConverterTo((Unit) GRAM); - } - } else if (CUBIC_METRE.equals(parentUnit)) { - if (converter != null) { - parentUnit = LITRE; - } - } - - if (unit instanceof TransformedUnit) { - TransformedUnit transUnit = (TransformedUnit) unit; - if (parentUnit == null) - parentUnit = transUnit.getParentUnit(); - // String x = parentUnit.toString(); - converter = transUnit.getConverter(); - } - - unitPrecedence = formatInternal(parentUnit, temp); - printSeparator = !parentUnit.equals(AbstractUnit.ONE); - int result = formatConverter(converter, printSeparator, unitPrecedence, temp); - buffer.append(temp); - return result; - } - } - - /** - * Format the given unit raised to the given fractional power to the given StringBuffer. - * - * @param unit - * Unit the unit to be formatted - * @param pow - * int the numerator of the fractional power - * @param root - * int the denominator of the fractional power - * @param continued - * boolean true if the converter expression should begin with an operator, otherwise false. This will always be - * true unless the unit being modified is equal to Unit.ONE. - * @param buffer - * StringBuffer the buffer to append to. No assumptions should be made about its content. - */ - private void formatExponent(Unit unit, int pow, int root, boolean continued, Appendable buffer) throws IOException { - if (continued) { - buffer.append(MIDDLE_DOT); - } - StringBuffer temp = new StringBuffer(); - int unitPrecedence = formatInternal(unit, temp); - if (unitPrecedence < PRODUCT_PRECEDENCE) { - temp.insert(0, '('); - temp.append(')'); - } - buffer.append(temp); - if ((root == 1) && (pow == 1)) { - // do nothing - } else if ((root == 1) && (pow > 1)) { - String powStr = Integer.toString(pow); - for (int i = 0; i < powStr.length(); i += 1) { - char c = powStr.charAt(i); - switch (c) { - case '0': - buffer.append('\u2070'); - break; - case '1': - buffer.append('\u00b9'); - break; - case '2': - buffer.append('\u00b2'); - break; - case '3': - buffer.append('\u00b3'); - break; - case '4': - buffer.append('\u2074'); - break; - case '5': - buffer.append('\u2075'); - break; - case '6': - buffer.append('\u2076'); - break; - case '7': - buffer.append('\u2077'); - break; - case '8': - buffer.append('\u2078'); - break; - case '9': - buffer.append('\u2079'); - break; - } - } - } else if (root == 1) { - buffer.append("^"); - buffer.append(String.valueOf(pow)); - } else { - buffer.append("^("); - buffer.append(String.valueOf(pow)); - buffer.append('/'); - buffer.append(String.valueOf(root)); - buffer.append(')'); - } - } - - /** - * Formats the given converter to the given StringBuffer and returns the operator precedence of the converter's mathematical operation. This is the - * default implementation, which supports all built-in UnitConverter implementations. Note that it recursively calls itself in the case of a - * {@link javax.measure.converter.UnitConverter.Compound Compound} converter. - * - * @param converter - * the converter to be formatted - * @param continued - * true if the converter expression should begin with an operator, otherwise false. - * @param unitPrecedence - * the operator precedence of the operation expressed by the unit being modified by the given converter. - * @param buffer - * the StringBuffer to append to. - * @return the operator precedence of the given UnitConverter - */ - private int formatConverter(UnitConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { - MetricPrefix prefix = symbolMap.getPrefix(converter); - if ((prefix != null) && (unitPrecedence == NOOP_PRECEDENCE)) { - buffer.insert(0, symbolMap.getSymbol(prefix)); - return NOOP_PRECEDENCE; - } else if (converter instanceof AddConverter) { - if (unitPrecedence < ADDITION_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - double offset = ((AddConverter) converter).getOffset(); - if (offset < 0) { - buffer.append("-"); - offset = -offset; - } else if (continued) { - buffer.append("+"); - } - long lOffset = (long) offset; - if (lOffset == offset) { - buffer.append(lOffset); - } else { - buffer.append(offset); - } - return ADDITION_PRECEDENCE; - } else if (converter instanceof MultiplyConverter) { - if (unitPrecedence < PRODUCT_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - if (continued) { - buffer.append(MIDDLE_DOT); - } - double factor = ((MultiplyConverter) converter).getFactor(); - long lFactor = (long) factor; - if (lFactor == factor) { - buffer.append(lFactor); - } else { - buffer.append(factor); - } - return PRODUCT_PRECEDENCE; - } else if (converter instanceof RationalConverter) { - if (unitPrecedence < PRODUCT_PRECEDENCE) { - buffer.insert(0, '('); - buffer.append(')'); - } - RationalConverter rationalConverter = (RationalConverter) converter; - if (!rationalConverter.getDividend().equals(BigInteger.ONE)) { - if (continued) { - buffer.append(MIDDLE_DOT); - } - buffer.append(rationalConverter.getDividend()); - } - if (!rationalConverter.getDivisor().equals(BigInteger.ONE)) { - buffer.append('/'); - buffer.append(rationalConverter.getDivisor()); - } - return PRODUCT_PRECEDENCE; - } else { // All other converter type (e.g. exponential) we use the - // string representation. - buffer.insert(0, converter.toString() + "("); - buffer.append(")"); - return EXPONENT_PRECEDENCE; - } - } +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import static tec.uom.se.unit.Units.CUBIC_METRE; +import static tec.uom.se.unit.Units.GRAM; +import static tec.uom.se.unit.Units.KILOGRAM; +import static tec.uom.se.unit.Units.LITRE; +import tec.uom.se.AbstractUnit; +import tec.uom.se.function.AddConverter; +import tec.uom.se.function.MultiplyConverter; +import tec.uom.se.function.RationalConverter; +import tec.uom.se.internal.format.TokenException; +import tec.uom.se.internal.format.TokenMgrError; +import tec.uom.se.internal.format.LocalUnitFormatParser; +import tec.uom.se.unit.AlternateUnit; +import tec.uom.se.unit.AnnotatedUnit; +import tec.uom.se.unit.BaseUnit; +import tec.uom.se.unit.MetricPrefix; +import tec.uom.se.unit.TransformedUnit; +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.UnitConverter; +import javax.measure.format.ParserException; + +import java.io.IOException; +import java.io.StringReader; +import java.math.BigInteger; +import java.text.ParsePosition; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +/** + *

+ * This class represents the local sensitive format. + *

+ * + *

Here is the grammar for CommonUnits in Extended Backus-Naur Form (EBNF)

+ *

+ * Note that the grammar has been left-factored to be suitable for use by a top-down parser generator such as JavaCC + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Lexical Entities:
<sign>:="+" | "-"
<digit>:="0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<superscript_digit>:="⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"
<integer>:=(<digit>)+
<number>:=(<sign>)? (<digit>)* (".")? (<digit>)+ (("e" | "E") (<sign>)? (<digit>)+)?
<exponent>:=( "^" ( <sign> )? <integer> )
+ * | ( "^(" (<sign>)? <integer> ( "/" (<sign>)? <integer> )? ")" )
+ * | ( <superscript_digit> )+
<initial_char>:=? Any Unicode character excluding the following: ASCII control & whitespace (\u0000 - \u0020), decimal digits '0'-'9', '(' + * (\u0028), ')' (\u0029), '*' (\u002A), '+' (\u002B), '-' (\u002D), '.' (\u002E), '/' (\u005C), ':' (\u003A), '^' + * (\u005E), '²' (\u00B2), '³' (\u00B3), '·' (\u00B7), '¹' (\u00B9), '⁰' (\u2070), '⁴' (\u2074), '⁵' (\u2075), '⁶' + * (\u2076), '⁷' (\u2077), '⁸' (\u2078), '⁹' (\u2079) ?
<unit_identifier>:=<initial_char> ( <initial_char> | <digit> )*
Non-Terminals:
<unit_expr>:=<compound_expr>
<compound_expr>:=<add_expr> ( ":" <add_expr> )*
<add_expr>:=( <number> <sign> )? <mul_expr> ( <sign> <number> )?
<mul_expr>:=<exponent_expr> ( ( ( "*" | "·" ) <exponent_expr> ) | ( "/" <exponent_expr> ) )*
<exponent_expr>:=( <atomic_expr> ( <exponent> )? )
+ * | (<integer> "^" <atomic_expr>)
+ * | ( ( "log" ( <integer> )? ) | "ln" ) "(" <add_expr> ")" )
<atomic_expr>:=<number>
+ * | <unit_identifier>
+ * | ( "(" <add_expr> ")" )
+ * + * @author Eric Russell + * @author Werner Keil + * @version 1.0.2, April 30, 2017 + * @since 1.0 + */ +public class LocalUnitFormat extends AbstractUnitFormat { + + // //////////////////////////////////////////////////// + // Class variables // + // //////////////////////////////////////////////////// + /** + * DefaultQuantityFactory locale instance. If the default locale is changed after the class is initialized, this instance will no longer be used. + */ + private static final LocalUnitFormat DEFAULT_INSTANCE = new LocalUnitFormat(SymbolMap.of(ResourceBundle.getBundle(LocalUnitFormat.class + .getPackage().getName() + ".messages"))); + /** + * Multiplicand character + */ + private static final char MIDDLE_DOT = '\u00b7'; + /** + * Operator precedence for the addition and subtraction operations + */ + private static final int ADDITION_PRECEDENCE = 0; + /** + * Operator precedence for the multiplication and division operations + */ + private static final int PRODUCT_PRECEDENCE = ADDITION_PRECEDENCE + 2; + /** + * Operator precedence for the exponentiation and logarithm operations + */ + private static final int EXPONENT_PRECEDENCE = PRODUCT_PRECEDENCE + 2; + /** + * Operator precedence for a unit identifier containing no mathematical operations (i.e., consisting exclusively of an identifier and possibly a + * prefix). Defined to be Integer.MAX_VALUE so that no operator can have a higher precedence. + */ + private static final int NOOP_PRECEDENCE = Integer.MAX_VALUE; + + // ///////////////// + // Class methods // + // ///////////////// + /** + * Returns the instance for the current default locale (non-ascii characters are allowed) + */ + public static LocalUnitFormat getInstance() { + return DEFAULT_INSTANCE; + } + + /** + * Returns an instance for the given locale. + * + * @param locale + */ + public static LocalUnitFormat getInstance(Locale locale) { + return new LocalUnitFormat(SymbolMap.of(ResourceBundle.getBundle(LocalUnitFormat.class.getPackage().getName() + ".messages", locale))); + } + + /** Returns an instance for the given symbol map. */ + public static LocalUnitFormat getInstance(SymbolMap symbols) { + return new LocalUnitFormat(symbols); + } + + // ////////////////////// + // Instance variables // + // ////////////////////// + /** + * The symbol map used by this instance to map between {@link Unit Unit}s and Strings, etc... + */ + private final transient SymbolMap symbolMap; + + // //////////////// + // Constructors // + // //////////////// + /** + * Base constructor. + * + * @param symbols + * the symbol mapping. + */ + private LocalUnitFormat(SymbolMap symbols) { + symbolMap = symbols; + } + + // ////////////////////// + // Instance methods // + // ////////////////////// + /** + * Get the symbol map used by this instance to map between {@link AbstractUnit Unit}s and Strings, etc... + * + * @return SymbolMap the current symbol map + */ + @Override + protected SymbolMap getSymbols() { + return symbolMap; + } + + // ////////////// + // Formatting // + // ////////////// + @Override + public Appendable format(Unit unit, Appendable appendable) throws IOException { + if (!(unit instanceof AbstractUnit)) { + return appendable.append(unit.toString()); // Unknown unit (use + // intrinsic toString() + // method) + } + formatInternal(unit, appendable); + return appendable; + } + + public boolean isLocaleSensitive() { + return true; + } + + protected Unit parse(CharSequence csq, int index) throws ParserException { + return parse(csq, new ParsePosition(index)); + } + + public Unit parse(CharSequence csq, ParsePosition cursor) throws ParserException { + // Parsing reads the whole character sequence from the parse position. + int start = cursor.getIndex(); + int end = csq.length(); + if (end <= start) { + return AbstractUnit.ONE; + } + String source = csq.subSequence(start, end).toString().trim(); + if (source.length() == 0) { + return AbstractUnit.ONE; + } + try { + LocalUnitFormatParser parser = new LocalUnitFormatParser(symbolMap, new StringReader(source)); + Unit result = parser.parseUnit(); + cursor.setIndex(end); + return result; + } catch (TokenException e) { + if (e.currentToken != null) { + cursor.setErrorIndex(start + e.currentToken.endColumn); + } else { + cursor.setErrorIndex(start); + } + throw new IllegalArgumentException(e); // TODO should we throw + // ParserException here, + // too? + } catch (TokenMgrError e) { + cursor.setErrorIndex(start); + throw new ParserException(e); + } + } + + @Override + public Unit> parse(CharSequence csq) throws ParserException { + return parse(csq, new ParsePosition(0)); + } + + /** + * Format the given unit to the given StringBuilder, then return the operator precedence of the outermost operator in the unit expression that was + * formatted. See {@link ConverterFormat} for the constants that define the various precedence values. + * + * @param unit + * the unit to be formatted + * @param buffer + * the StringBuilder to be written to + * @return the operator precedence of the outermost operator in the unit expression that was output + */ + /* + * private int formatInternal(Unit unit, Appendable buffer) throws + * IOException { if (unit instanceof AnnotatedUnit) { unit = + * ((AnnotatedUnit) unit).getActualUnit(); } String symbol = + * symbolMap.getSymbol((AbstractUnit) unit); if (symbol != null) { + * buffer.append(symbol); return NOOP_PRECEDENCE; } else if + * (unit.getBaseUnits() != null) { Map productUnits + * = unit.getBaseUnits(); int negativeExponentCount = 0; // Write positive + * exponents first... boolean start = true; for (Unit u : + * productUnits.keySet()) { int pow = productUnits.get(u); if (pow >= 0) { + * formatExponent(u, pow, 1, !start, buffer); start = false; } else { + * negativeExponentCount += 1; } } // ..then write negative exponents. if + * (negativeExponentCount > 0) { if (start) { buffer.append('1'); } + * buffer.append('/'); if (negativeExponentCount > 1) { buffer.append('('); + * } start = true; for (Unit u : productUnits.keySet()) { int pow = + * productUnits.get(u); if (pow < 0) { formatExponent(u, -pow, 1, !start, + * buffer); start = false; } } if (negativeExponentCount > 1) { + * buffer.append(')'); } } return PRODUCT_PRECEDENCE; } else if + * ((!((AbstractUnit)unit).isSystemUnit()) || unit.equals(Units.KILOGRAM)) { + * UnitConverter converter = null; boolean printSeparator = false; + * StringBuffer temp = new StringBuffer(); int unitPrecedence = + * NOOP_PRECEDENCE; if (unit.equals(Units.KILOGRAM)) { // A special case + * because KILOGRAM is a BaseUnit instead of // a transformed unit, even + * though it has a prefix. converter = MetricPrefix.KILO.getConverter(); + * unitPrecedence = formatInternal(Units.GRAM, temp); printSeparator = true; + * } else { Unit parentUnit = unit.getSystemUnit(); converter = + * unit.getConverterTo(parentUnit); if (parentUnit.equals(Units.KILOGRAM)) { + * // More special-case hackery to work around gram/kilogram // incosistency + * parentUnit = Units.GRAM; converter = + * converter.concatenate(MetricPrefix.KILO.getConverter()); } unitPrecedence + * = formatInternal(parentUnit, temp); printSeparator = + * !parentUnit.equals(Units.ONE); } int result = formatConverter(converter, + * printSeparator, unitPrecedence, temp); buffer.append(temp); return + * result; } else if (unit.getSymbol() != null) { + * buffer.append(unit.getSymbol()); return NOOP_PRECEDENCE; } else { throw + * new IllegalArgumentException( + * "Cannot format the given Object as a Unit (unsupported unit type " + + * unit.getClass().getName() + ")"); } } + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private int formatInternal(Unit unit, Appendable buffer) throws IOException { + if (unit instanceof AnnotatedUnit) { + unit = ((AnnotatedUnit) unit).getActualUnit(); + // } else if (unit instanceof ProductUnit) { + // ProductUnit p = (ProductUnit)unit; + } + String symbol = symbolMap.getSymbol((AbstractUnit) unit); + if (symbol != null) { + buffer.append(symbol); + return NOOP_PRECEDENCE; + } else if (unit.getBaseUnits() != null) { + Map, Integer> productUnits = (Map, Integer>) unit.getBaseUnits(); + int negativeExponentCount = 0; + // Write positive exponents first... + boolean start = true; + for (Map.Entry, Integer> e : productUnits.entrySet()) { + int pow = e.getValue(); + if (pow >= 0) { + formatExponent(e.getKey(), pow, 1, !start, buffer); + start = false; + } else { + negativeExponentCount += 1; + } + } + // ..then write negative exponents. + if (negativeExponentCount > 0) { + if (start) { + buffer.append('1'); + } + buffer.append('/'); + if (negativeExponentCount > 1) { + buffer.append('('); + } + start = true; + for (Map.Entry, Integer> e : productUnits.entrySet()) { + int pow = e.getValue(); + if (pow < 0) { + formatExponent(e.getKey(), -pow, 1, !start, buffer); + start = false; + } + } + if (negativeExponentCount > 1) { + buffer.append(')'); + } + } + return PRODUCT_PRECEDENCE; + } else if (unit instanceof BaseUnit) { + buffer.append(((BaseUnit) unit).getSymbol()); + return NOOP_PRECEDENCE; + } else if (unit instanceof AlternateUnit) { // unit.getSymbol() != + // null) { // Alternate + // unit. + buffer.append(unit.getSymbol()); + return NOOP_PRECEDENCE; + } else { // A transformed unit or new unit type! + UnitConverter converter = null; + boolean printSeparator = false; + StringBuilder temp = new StringBuilder(); + int unitPrecedence = NOOP_PRECEDENCE; + Unit parentUnit = unit.getSystemUnit(); + converter = ((AbstractUnit) unit).getSystemConverter(); + if (KILOGRAM.equals(parentUnit)) { + // More special-case hackery to work around gram/kilogram + // incosistency + if (unit.equals(GRAM)) { + buffer.append(symbolMap.getSymbol(GRAM)); + return NOOP_PRECEDENCE; + } + parentUnit = GRAM; + if (unit instanceof TransformedUnit) { + converter = ((TransformedUnit) unit).getConverter(); + } else { + converter = unit.getConverterTo((Unit) GRAM); + } + } else if (CUBIC_METRE.equals(parentUnit)) { + if (converter != null) { + parentUnit = LITRE; + } + } + + if (unit instanceof TransformedUnit) { + TransformedUnit transUnit = (TransformedUnit) unit; + if (parentUnit == null) + parentUnit = transUnit.getParentUnit(); + // String x = parentUnit.toString(); + converter = transUnit.getConverter(); + } + + unitPrecedence = formatInternal(parentUnit, temp); + printSeparator = !parentUnit.equals(AbstractUnit.ONE); + int result = formatConverter(converter, printSeparator, unitPrecedence, temp); + buffer.append(temp); + return result; + } + } + + /** + * Format the given unit raised to the given fractional power to the given StringBuffer. + * + * @param unit + * Unit the unit to be formatted + * @param pow + * int the numerator of the fractional power + * @param root + * int the denominator of the fractional power + * @param continued + * boolean true if the converter expression should begin with an operator, otherwise false. This will always be + * true unless the unit being modified is equal to Unit.ONE. + * @param buffer + * StringBuffer the buffer to append to. No assumptions should be made about its content. + */ + private void formatExponent(Unit unit, int pow, int root, boolean continued, Appendable buffer) throws IOException { + if (continued) { + buffer.append(MIDDLE_DOT); + } + StringBuffer temp = new StringBuffer(); + int unitPrecedence = formatInternal(unit, temp); + if (unitPrecedence < PRODUCT_PRECEDENCE) { + temp.insert(0, '('); + temp.append(')'); + } + buffer.append(temp); + if ((root == 1) && (pow == 1)) { + // do nothing + } else if ((root == 1) && (pow > 1)) { + String powStr = Integer.toString(pow); + for (int i = 0; i < powStr.length(); i += 1) { + char c = powStr.charAt(i); + switch (c) { + case '0': + buffer.append('\u2070'); + break; + case '1': + buffer.append('\u00b9'); + break; + case '2': + buffer.append('\u00b2'); + break; + case '3': + buffer.append('\u00b3'); + break; + case '4': + buffer.append('\u2074'); + break; + case '5': + buffer.append('\u2075'); + break; + case '6': + buffer.append('\u2076'); + break; + case '7': + buffer.append('\u2077'); + break; + case '8': + buffer.append('\u2078'); + break; + case '9': + buffer.append('\u2079'); + break; + } + } + } else if (root == 1) { + buffer.append("^"); + buffer.append(String.valueOf(pow)); + } else { + buffer.append("^("); + buffer.append(String.valueOf(pow)); + buffer.append('/'); + buffer.append(String.valueOf(root)); + buffer.append(')'); + } + } + + /** + * Formats the given converter to the given StringBuffer and returns the operator precedence of the converter's mathematical operation. This is the + * default implementation, which supports all built-in UnitConverter implementations. Note that it recursively calls itself in the case of a + * {@link javax.measure.converter.UnitConverter.Compound Compound} converter. + * + * @param converter + * the converter to be formatted + * @param continued + * true if the converter expression should begin with an operator, otherwise false. + * @param unitPrecedence + * the operator precedence of the operation expressed by the unit being modified by the given converter. + * @param buffer + * the StringBuffer to append to. + * @return the operator precedence of the given UnitConverter + */ + private int formatConverter(UnitConverter converter, boolean continued, int unitPrecedence, StringBuilder buffer) { + MetricPrefix prefix = symbolMap.getPrefix(converter); + if ((prefix != null) && (unitPrecedence == NOOP_PRECEDENCE)) { + buffer.insert(0, symbolMap.getSymbol(prefix)); + return NOOP_PRECEDENCE; + } else if (converter instanceof AddConverter) { + if (unitPrecedence < ADDITION_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + double offset = ((AddConverter) converter).getOffset(); + if (offset < 0) { + buffer.append("-"); + offset = -offset; + } else if (continued) { + buffer.append("+"); + } + long lOffset = (long) offset; + if (lOffset == offset) { + buffer.append(lOffset); + } else { + buffer.append(offset); + } + return ADDITION_PRECEDENCE; + } else if (converter instanceof MultiplyConverter) { + if (unitPrecedence < PRODUCT_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + if (continued) { + buffer.append(MIDDLE_DOT); + } + double factor = ((MultiplyConverter) converter).getFactor(); + long lFactor = (long) factor; + if (lFactor == factor) { + buffer.append(lFactor); + } else { + buffer.append(factor); + } + return PRODUCT_PRECEDENCE; + } else if (converter instanceof RationalConverter) { + if (unitPrecedence < PRODUCT_PRECEDENCE) { + buffer.insert(0, '('); + buffer.append(')'); + } + RationalConverter rationalConverter = (RationalConverter) converter; + if (!rationalConverter.getDividend().equals(BigInteger.ONE)) { + if (continued) { + buffer.append(MIDDLE_DOT); + } + buffer.append(rationalConverter.getDividend()); + } + if (!rationalConverter.getDivisor().equals(BigInteger.ONE)) { + buffer.append('/'); + buffer.append(rationalConverter.getDivisor()); + } + return PRODUCT_PRECEDENCE; + } else { // All other converter type (e.g. exponential) we use the + // string representation. + buffer.insert(0, converter.toString() + "("); + buffer.append(")"); + return EXPONENT_PRECEDENCE; + } + } } \ No newline at end of file diff --git a/src/main/java/tec/uom/se/format/NumberSpaceQuantityFormat.java b/src/main/java/tec/uom/se/format/NumberSpaceQuantityFormat.java index 57f278db..7a26d546 100644 --- a/src/main/java/tec/uom/se/format/NumberSpaceQuantityFormat.java +++ b/src/main/java/tec/uom/se/format/NumberSpaceQuantityFormat.java @@ -1,118 +1,118 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import java.io.IOException; -import java.text.NumberFormat; -import java.text.ParsePosition; - -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.format.ParserException; -import javax.measure.format.UnitFormat; - -import tec.uom.se.AbstractUnit; -import tec.uom.se.ComparableQuantity; -import tec.uom.se.quantity.Quantities; - -@SuppressWarnings({ "rawtypes", "unchecked" }) -class NumberSpaceQuantityFormat extends QuantityFormat { - - private final NumberFormat numberFormat; - - private final UnitFormat unitFormat; - - NumberSpaceQuantityFormat(NumberFormat numberFormat, UnitFormat unitFormat) { - this.numberFormat = numberFormat; - this.unitFormat = unitFormat; - } - - static int getFractionDigitsCount(double d) { - if (d >= 1) { // we only need the fraction digits - d = d - (long) d; - } - if (d == 0) { // nothing to count - return 0; - } - d *= 10; // shifts 1 digit to left - int count = 1; - while (d - (long) d != 0) { // keeps shifting until there are no more - // fractions - d *= 10; - count++; - } - return count; - } - - @Override - public Appendable format(Quantity quantity, Appendable dest) throws IOException { - // dest.append(numberFormat.format(quantity.getValue())); - // if (quantity.getUnit().equals(AbstractUnit.ONE)) - // return dest; - // dest.append(' '); - // return unitFormat.format(quantity.getUnit(), dest); - int fract = 0; - if (quantity != null && quantity.getValue() != null) { - fract = getFractionDigitsCount(quantity.getValue().doubleValue()); - } - if (fract > 1) { - numberFormat.setMaximumFractionDigits(fract + 1); - } - dest.append(numberFormat.format(quantity.getValue())); - if (quantity.getUnit().equals(AbstractUnit.ONE)) - return dest; - dest.append(' '); - return unitFormat.format(quantity.getUnit(), dest); - } - - @Override - public ComparableQuantity parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException, ParserException { - String str = csq.toString(); - Number number = numberFormat.parse(str, cursor); - if (number == null) - throw new IllegalArgumentException("Number cannot be parsed"); - - Unit unit = unitFormat.parse(csq); - return Quantities.getQuantity(number.longValue(), unit); - } - - @Override - ComparableQuantity parse(CharSequence csq, int index) throws IllegalArgumentException, ParserException { - return parse(csq, new ParsePosition(index)); - } - - @Override - public ComparableQuantity parse(CharSequence csq) throws IllegalArgumentException, ParserException { - return parse(csq, 0); - } - - private static final long serialVersionUID = 1L; - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import java.io.IOException; +import java.text.NumberFormat; +import java.text.ParsePosition; + +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.format.ParserException; +import javax.measure.format.UnitFormat; + +import tec.uom.se.AbstractUnit; +import tec.uom.se.ComparableQuantity; +import tec.uom.se.quantity.Quantities; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +class NumberSpaceQuantityFormat extends QuantityFormat { + + private final NumberFormat numberFormat; + + private final UnitFormat unitFormat; + + NumberSpaceQuantityFormat(NumberFormat numberFormat, UnitFormat unitFormat) { + this.numberFormat = numberFormat; + this.unitFormat = unitFormat; + } + + static int getFractionDigitsCount(double d) { + if (d >= 1) { // we only need the fraction digits + d = d - (long) d; + } + if (d == 0) { // nothing to count + return 0; + } + d *= 10; // shifts 1 digit to left + int count = 1; + while (d - (long) d != 0) { // keeps shifting until there are no more + // fractions + d *= 10; + count++; + } + return count; + } + + @Override + public Appendable format(Quantity quantity, Appendable dest) throws IOException { + // dest.append(numberFormat.format(quantity.getValue())); + // if (quantity.getUnit().equals(AbstractUnit.ONE)) + // return dest; + // dest.append(' '); + // return unitFormat.format(quantity.getUnit(), dest); + int fract = 0; + if (quantity != null && quantity.getValue() != null) { + fract = getFractionDigitsCount(quantity.getValue().doubleValue()); + } + if (fract > 1) { + numberFormat.setMaximumFractionDigits(fract + 1); + } + dest.append(numberFormat.format(quantity.getValue())); + if (quantity.getUnit().equals(AbstractUnit.ONE)) + return dest; + dest.append(' '); + return unitFormat.format(quantity.getUnit(), dest); + } + + @Override + public ComparableQuantity parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException, ParserException { + String str = csq.toString(); + Number number = numberFormat.parse(str, cursor); + if (number == null) + throw new IllegalArgumentException("Number cannot be parsed"); + + Unit unit = unitFormat.parse(csq); + return Quantities.getQuantity(number.longValue(), unit); + } + + @Override + ComparableQuantity parse(CharSequence csq, int index) throws IllegalArgumentException, ParserException { + return parse(csq, new ParsePosition(index)); + } + + @Override + public ComparableQuantity parse(CharSequence csq) throws IllegalArgumentException, ParserException { + return parse(csq, 0); + } + + private static final long serialVersionUID = 1L; + } \ No newline at end of file diff --git a/src/main/java/tec/uom/se/format/QuantityFormat.java b/src/main/java/tec/uom/se/format/QuantityFormat.java index 97302ee1..ce1f6639 100644 --- a/src/main/java/tec/uom/se/format/QuantityFormat.java +++ b/src/main/java/tec/uom/se/format/QuantityFormat.java @@ -1,219 +1,219 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import java.io.IOException; -import java.math.BigDecimal; -import java.text.FieldPosition; -import java.text.Format; -import java.text.NumberFormat; -import java.text.ParsePosition; - -import javax.measure.Quantity; -import javax.measure.Unit; -import javax.measure.format.ParserException; -import javax.measure.format.UnitFormat; - -import tec.uom.lib.common.function.Parser; -import tec.uom.se.AbstractQuantity; -import tec.uom.se.ComparableQuantity; - -/** - *

- * This class provides the interface for formatting and parsing {@link Quantity quantities}. - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0.1, $Date: 2017-07-10 $ - * @since 1.0 - * - */ -@SuppressWarnings("rawtypes") -public abstract class QuantityFormat extends Format implements Parser { - // TODO for later, see https://github.com/unitsofmeasurement/uom-se/issues/162 - // *

- // * Instances of this class should be able to format quantities stated in {@link CompoundUnit}. See {@link #formatCompound formatCompound(...)}. - // *

- +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import java.io.IOException; +import java.math.BigDecimal; +import java.text.FieldPosition; +import java.text.Format; +import java.text.NumberFormat; +import java.text.ParsePosition; + +import javax.measure.Quantity; +import javax.measure.Unit; +import javax.measure.format.ParserException; +import javax.measure.format.UnitFormat; + +import tec.uom.lib.common.function.Parser; +import tec.uom.se.AbstractQuantity; +import tec.uom.se.ComparableQuantity; + +/** + *

+ * This class provides the interface for formatting and parsing {@link Quantity quantities}. + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0.1, $Date: 2017-07-10 $ + * @since 1.0 + * + */ +@SuppressWarnings("rawtypes") +public abstract class QuantityFormat extends Format implements Parser { + // TODO for later, see https://github.com/unitsofmeasurement/uom-se/issues/162 + // *

+ // * Instances of this class should be able to format quantities stated in {@link CompoundUnit}. See {@link #formatCompound formatCompound(...)}. + // *

+ /** * - */ - private static final long serialVersionUID = -4628006924354248662L; - - /** - * Holds the localized format instance. - */ - private static final NumberSpaceQuantityFormat LOCAL = new NumberSpaceQuantityFormat(NumberFormat.getInstance(), LocalUnitFormat.getInstance()); - - /** - * Holds the default format instance. - */ - private static final DefaultQuantityFormat DEFAULT = new DefaultQuantityFormat(); - - /** - * Returns the quantity format for the default locale. The default format assumes the quantity is composed of a decimal number and a {@link Unit} - * separated by whitespace(s). - * - * @return MeasureFormat.getInstance(NumberFormat.getInstance(), UnitFormat.getInstance()) - */ - public static QuantityFormat getInstance() { - return DEFAULT; - } - - /** - * Returns the quantity format using the specified number format and unit format (the number and unit are separated by one space). - * - * @param numberFormat - * the number format. - * @param unitFormat - * the unit format. - * @return the corresponding format. - */ - public static QuantityFormat getInstance(NumberFormat numberFormat, UnitFormat unitFormat) { - return new NumberSpaceQuantityFormat(numberFormat, unitFormat); - } - - /** - * Returns the culture invariant format based upon {@link BigDecimal} canonical format and the {@link UnitFormat#getStandardInstance() standard} - * unit format. This format is not locale-sensitive and can be used for unambiguous electronic communication of quantities together with - * their units without loss of information. For example: "1.23456789 kg.m/s2" returns - * Quantities.getQuantity(new BigDecimal("1.23456789"), AbstractUnit.parse("kg.m/s2"))); - * - * @param style - * the format style to apply. - * @return the desired format. - */ - public static QuantityFormat getInstance(FormatBehavior style) { - switch (style) { - case LOCALE_NEUTRAL: - return DEFAULT; - case LOCALE_SENSITIVE: - return LOCAL; - default: - return DEFAULT; - } - } - - /** - * Formats the specified quantity into an Appendable. - * - * @param quantity - * the quantity to format. - * @param dest - * the appendable destination. - * @return the specified Appendable. - * @throws IOException - * if an I/O exception occurs. - */ - public abstract Appendable format(Quantity quantity, Appendable dest) throws IOException; - - /** - * Parses a portion of the specified CharSequence from the specified position to produce an object. If parsing succeeds, then the index - * of the cursor argument is updated to the index after the last character used. - * - * @param csq - * the CharSequence to parse. - * @param cursor - * the cursor holding the current parsing index. - * @return the object parsed from the specified character sub-sequence. - * @throws IllegalArgumentException - * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). - */ - public abstract ComparableQuantity parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException, ParserException; - - /** - * Parses a portion of the specified CharSequence from the specified position to produce an object. If parsing succeeds, then the index - * of the cursor argument is updated to the index after the last character used. - * - * @param csq - * the CharSequence to parse. - * @param cursor - * the cursor holding the current parsing index. - * @return the object parsed from the specified character sub-sequence. - * @throws IllegalArgumentException - * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). - */ - @Override - public abstract ComparableQuantity parse(CharSequence csq) throws IllegalArgumentException, ParserException; - - /** - * Parses a portion of the specified CharSequence from the specified position to produce an object. If parsing succeeds, then the index - * of the cursor argument is updated to the index after the last character used. - * - * @param csq - * the CharSequence to parse. - * @param index - * the current parsing index. - * @return the object parsed from the specified character sub-sequence. - * @throws IllegalArgumentException - * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). - */ - abstract ComparableQuantity parse(CharSequence csq, int index) throws IllegalArgumentException, ParserException; - - @Override - public final StringBuffer format(Object obj, final StringBuffer toAppendTo, FieldPosition pos) { - if (!(obj instanceof AbstractQuantity)) - throw new IllegalArgumentException("obj: Not an instance of Quantity"); - if ((toAppendTo == null) || (pos == null)) - throw new NullPointerException(); - try { - return (StringBuffer) format((AbstractQuantity) obj, toAppendTo); - } catch (IOException ex) { - throw new Error(ex); // Cannot happen. - } - } - - @Override - public final Quantity parseObject(String source, ParsePosition pos) { - try { - return parse(source, pos); - } catch (IllegalArgumentException | ParserException e) { - return null; - } - } - - /** - * Convenience method equivalent to {@link #format(AbstractQuantity, Appendable)} except it does not raise an IOException. - * - * @param quantity - * the quantity to format. - * @param dest - * the appendable destination. - * @return the specified StringBuilder. - */ - public final StringBuilder format(AbstractQuantity quantity, StringBuilder dest) { - try { - return (StringBuilder) this.format(quantity, (Appendable) dest); - } catch (IOException ex) { - throw new RuntimeException(ex); // Should not happen. - } - } -} + */ + private static final long serialVersionUID = -4628006924354248662L; + + /** + * Holds the localized format instance. + */ + private static final NumberSpaceQuantityFormat LOCAL = new NumberSpaceQuantityFormat(NumberFormat.getInstance(), LocalUnitFormat.getInstance()); + + /** + * Holds the default format instance. + */ + private static final DefaultQuantityFormat DEFAULT = new DefaultQuantityFormat(); + + /** + * Returns the quantity format for the default locale. The default format assumes the quantity is composed of a decimal number and a {@link Unit} + * separated by whitespace(s). + * + * @return MeasureFormat.getInstance(NumberFormat.getInstance(), UnitFormat.getInstance()) + */ + public static QuantityFormat getInstance() { + return DEFAULT; + } + + /** + * Returns the quantity format using the specified number format and unit format (the number and unit are separated by one space). + * + * @param numberFormat + * the number format. + * @param unitFormat + * the unit format. + * @return the corresponding format. + */ + public static QuantityFormat getInstance(NumberFormat numberFormat, UnitFormat unitFormat) { + return new NumberSpaceQuantityFormat(numberFormat, unitFormat); + } + + /** + * Returns the culture invariant format based upon {@link BigDecimal} canonical format and the {@link UnitFormat#getStandardInstance() standard} + * unit format. This format is not locale-sensitive and can be used for unambiguous electronic communication of quantities together with + * their units without loss of information. For example: "1.23456789 kg.m/s2" returns + * Quantities.getQuantity(new BigDecimal("1.23456789"), AbstractUnit.parse("kg.m/s2"))); + * + * @param style + * the format style to apply. + * @return the desired format. + */ + public static QuantityFormat getInstance(FormatBehavior style) { + switch (style) { + case LOCALE_NEUTRAL: + return DEFAULT; + case LOCALE_SENSITIVE: + return LOCAL; + default: + return DEFAULT; + } + } + + /** + * Formats the specified quantity into an Appendable. + * + * @param quantity + * the quantity to format. + * @param dest + * the appendable destination. + * @return the specified Appendable. + * @throws IOException + * if an I/O exception occurs. + */ + public abstract Appendable format(Quantity quantity, Appendable dest) throws IOException; + + /** + * Parses a portion of the specified CharSequence from the specified position to produce an object. If parsing succeeds, then the index + * of the cursor argument is updated to the index after the last character used. + * + * @param csq + * the CharSequence to parse. + * @param cursor + * the cursor holding the current parsing index. + * @return the object parsed from the specified character sub-sequence. + * @throws IllegalArgumentException + * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). + */ + public abstract ComparableQuantity parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException, ParserException; + + /** + * Parses a portion of the specified CharSequence from the specified position to produce an object. If parsing succeeds, then the index + * of the cursor argument is updated to the index after the last character used. + * + * @param csq + * the CharSequence to parse. + * @param cursor + * the cursor holding the current parsing index. + * @return the object parsed from the specified character sub-sequence. + * @throws IllegalArgumentException + * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). + */ + @Override + public abstract ComparableQuantity parse(CharSequence csq) throws IllegalArgumentException, ParserException; + + /** + * Parses a portion of the specified CharSequence from the specified position to produce an object. If parsing succeeds, then the index + * of the cursor argument is updated to the index after the last character used. + * + * @param csq + * the CharSequence to parse. + * @param index + * the current parsing index. + * @return the object parsed from the specified character sub-sequence. + * @throws IllegalArgumentException + * if any problem occurs while parsing the specified character sequence (e.g. illegal syntax). + */ + abstract ComparableQuantity parse(CharSequence csq, int index) throws IllegalArgumentException, ParserException; + + @Override + public final StringBuffer format(Object obj, final StringBuffer toAppendTo, FieldPosition pos) { + if (!(obj instanceof AbstractQuantity)) + throw new IllegalArgumentException("obj: Not an instance of Quantity"); + if ((toAppendTo == null) || (pos == null)) + throw new NullPointerException(); + try { + return (StringBuffer) format((AbstractQuantity) obj, toAppendTo); + } catch (IOException ex) { + throw new Error(ex); // Cannot happen. + } + } + + @Override + public final Quantity parseObject(String source, ParsePosition pos) { + try { + return parse(source, pos); + } catch (IllegalArgumentException | ParserException e) { + return null; + } + } + + /** + * Convenience method equivalent to {@link #format(AbstractQuantity, Appendable)} except it does not raise an IOException. + * + * @param quantity + * the quantity to format. + * @param dest + * the appendable destination. + * @return the specified StringBuilder. + */ + public final StringBuilder format(AbstractQuantity quantity, StringBuilder dest) { + try { + return (StringBuilder) this.format(quantity, (Appendable) dest); + } catch (IOException ex) { + throw new RuntimeException(ex); // Should not happen. + } + } +} diff --git a/src/main/java/tec/uom/se/format/SimpleUnitFormat.java b/src/main/java/tec/uom/se/format/SimpleUnitFormat.java index 98fd58c0..bc844d93 100644 --- a/src/main/java/tec/uom/se/format/SimpleUnitFormat.java +++ b/src/main/java/tec/uom/se/format/SimpleUnitFormat.java @@ -1,978 +1,978 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import static tec.uom.se.unit.MetricPrefix.*; - -import java.io.IOException; -import java.lang.CharSequence; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.util.HashMap; -import java.util.Map; - -import tec.uom.se.AbstractUnit; -import tec.uom.se.function.AddConverter; -import tec.uom.se.function.MultiplyConverter; -import tec.uom.se.function.RationalConverter; -import tec.uom.se.unit.AlternateUnit; -import tec.uom.se.unit.BaseUnit; -import tec.uom.se.unit.ProductUnit; -import tec.uom.se.unit.TransformedUnit; -import tec.uom.se.unit.Units; -import tec.uom.se.unit.MetricPrefix; - -import javax.measure.Unit; -import javax.measure.UnitConverter; -import javax.measure.Quantity; -import javax.measure.format.ParserException; -import javax.measure.format.UnitFormat; - -/** - *

- * This class implements the {@link UnitFormat} interface for formatting and parsing {@link Unit units}. - *

- * - *

- * For all SI units, the 20 SI prefixes used to form decimal multiples and sub-multiples of SI units are recognized. {@link Units} are directly - * recognized. For example:
+/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import static tec.uom.se.unit.MetricPrefix.*; + +import java.io.IOException; +import java.lang.CharSequence; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.util.HashMap; +import java.util.Map; + +import tec.uom.se.AbstractUnit; +import tec.uom.se.function.AddConverter; +import tec.uom.se.function.MultiplyConverter; +import tec.uom.se.function.RationalConverter; +import tec.uom.se.unit.AlternateUnit; +import tec.uom.se.unit.BaseUnit; +import tec.uom.se.unit.ProductUnit; +import tec.uom.se.unit.TransformedUnit; +import tec.uom.se.unit.Units; +import tec.uom.se.unit.MetricPrefix; + +import javax.measure.Unit; +import javax.measure.UnitConverter; +import javax.measure.Quantity; +import javax.measure.format.ParserException; +import javax.measure.format.UnitFormat; + +/** + *

+ * This class implements the {@link UnitFormat} interface for formatting and parsing {@link Unit units}. + *

+ * + *

+ * For all SI units, the 20 SI prefixes used to form decimal multiples and sub-multiples of SI units are recognized. {@link Units} are directly + * recognized. For example:
* * AbstractUnit.parse("m°C").equals(MetricPrefix.MILLI(Units.CELSIUS)) * AbstractUnit.parse("kW").equals(MetricPrefix.KILO(Units.WATT)) - * AbstractUnit.parse("ft").equals(Units.METRE.multiply(0.3048)) - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @author Eric Russell - * @version 1.0.3, June 7, 2017 - * @since 1.0 - */ -public abstract class SimpleUnitFormat extends AbstractUnitFormat { + * AbstractUnit.parse("ft").equals(Units.METRE.multiply(0.3048)) + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @author Eric Russell + * @version 1.0.3, June 7, 2017 + * @since 1.0 + */ +public abstract class SimpleUnitFormat extends AbstractUnitFormat { /** * - */ - // private static final long serialVersionUID = 4149424034841739785L; - - /** - * Flavor of this format - * - * @author Werner - * - */ - public enum Flavor { - Default, ASCII - } - - /** - * Holds the standard unit format. - */ - private static final DefaultFormat DEFAULT = new DefaultFormat(); - - /** - * Holds the ASCIIFormat unit format. - */ - private static final ASCIIFormat ASCII = new ASCIIFormat(); - - /** - * Returns the unit format for the default locale (format used by {@link AbstractUnit#parse(CharSequence) AbstractUnit.parse(CharSequence)} and - * {@link Unit#toString() Unit.toString()}). - * - * @return the default unit format (locale sensitive). - */ - public static SimpleUnitFormat getInstance() { - return getInstance(Flavor.Default); - } - - /** - * Returns the {@link SimpleUnitFormat} in the desired {@link Flavor} - * - * @return the instance for the given {@link Flavor}. - */ - public static SimpleUnitFormat getInstance(Flavor flavor) { - switch (flavor) { - case ASCII: - return SimpleUnitFormat.ASCII; - default: - return DEFAULT; - } - } - - /** - * Base constructor. - */ - protected SimpleUnitFormat() { - } - - /** - * Formats the specified unit. - * - * @param unit - * the unit to format. - * @param appendable - * the appendable destination. - * @throws IOException - * if an error occurs. - */ - public abstract Appendable format(Unit unit, Appendable appendable) throws IOException; - - /** - * Parses a sequence of character to produce a unit or a rational product of unit. - * - * @param csq - * the CharSequence to parse. - * @param pos - * an object holding the parsing index and error position. - * @return an {@link Unit} parsed from the character sequence. - * @throws IllegalArgumentException - * if the character sequence contains an illegal syntax. - */ - @SuppressWarnings("rawtypes") - public abstract Unit parseProductUnit(CharSequence csq, ParsePosition pos) throws ParserException; - - /** - * Parses a sequence of character to produce a single unit. - * - * @param csq - * the CharSequence to parse. - * @param pos - * an object holding the parsing index and error position. - * @return an {@link Unit} parsed from the character sequence. - * @throws IllegalArgumentException - * if the character sequence does not contain a valid unit identifier. - */ - @SuppressWarnings("rawtypes") - public abstract Unit parseSingleUnit(CharSequence csq, ParsePosition pos) throws ParserException; - - /** + */ + // private static final long serialVersionUID = 4149424034841739785L; + + /** + * Flavor of this format + * + * @author Werner + * + */ + public enum Flavor { + Default, ASCII + } + + /** + * Holds the standard unit format. + */ + private static final DefaultFormat DEFAULT = new DefaultFormat(); + + /** + * Holds the ASCIIFormat unit format. + */ + private static final ASCIIFormat ASCII = new ASCIIFormat(); + + /** + * Returns the unit format for the default locale (format used by {@link AbstractUnit#parse(CharSequence) AbstractUnit.parse(CharSequence)} and + * {@link Unit#toString() Unit.toString()}). + * + * @return the default unit format (locale sensitive). + */ + public static SimpleUnitFormat getInstance() { + return getInstance(Flavor.Default); + } + + /** + * Returns the {@link SimpleUnitFormat} in the desired {@link Flavor} + * + * @return the instance for the given {@link Flavor}. + */ + public static SimpleUnitFormat getInstance(Flavor flavor) { + switch (flavor) { + case ASCII: + return SimpleUnitFormat.ASCII; + default: + return DEFAULT; + } + } + + /** + * Base constructor. + */ + protected SimpleUnitFormat() { + } + + /** + * Formats the specified unit. + * + * @param unit + * the unit to format. + * @param appendable + * the appendable destination. + * @throws IOException + * if an error occurs. + */ + public abstract Appendable format(Unit unit, Appendable appendable) throws IOException; + + /** + * Parses a sequence of character to produce a unit or a rational product of unit. + * + * @param csq + * the CharSequence to parse. + * @param pos + * an object holding the parsing index and error position. + * @return an {@link Unit} parsed from the character sequence. + * @throws IllegalArgumentException + * if the character sequence contains an illegal syntax. + */ + @SuppressWarnings("rawtypes") + public abstract Unit parseProductUnit(CharSequence csq, ParsePosition pos) throws ParserException; + + /** + * Parses a sequence of character to produce a single unit. + * + * @param csq + * the CharSequence to parse. + * @param pos + * an object holding the parsing index and error position. + * @return an {@link Unit} parsed from the character sequence. + * @throws IllegalArgumentException + * if the character sequence does not contain a valid unit identifier. + */ + @SuppressWarnings("rawtypes") + public abstract Unit parseSingleUnit(CharSequence csq, ParsePosition pos) throws ParserException; + + /** * Attaches a system-wide label to the specified unit. For example: SimpleUnitFormat.getInstance().label(DAY.multiply(365), "year"); - * SimpleUnitFormat.getInstance().label(METER.multiply(0.3048), "ft"); If the specified label is already associated to an unit the previous - * association is discarded or ignored. - * - * @param unit - * the unit being labeled. - * @param label - * the new label for this unit. - * @throws IllegalArgumentException - * if the label is not a {@link SimpleUnitFormat#isValidIdentifier(String)} valid identifier. - */ - public abstract void label(Unit unit, String label); - - public boolean isLocaleSensitive() { - return false; - } - - /** - * Attaches a system-wide alias to this unit. Multiple aliases may be attached to the same unit. Aliases are used during parsing to recognize + * SimpleUnitFormat.getInstance().label(METER.multiply(0.3048), "ft"); If the specified label is already associated to an unit the previous + * association is discarded or ignored. + * + * @param unit + * the unit being labeled. + * @param label + * the new label for this unit. + * @throws IllegalArgumentException + * if the label is not a {@link SimpleUnitFormat#isValidIdentifier(String)} valid identifier. + */ + public abstract void label(Unit unit, String label); + + public boolean isLocaleSensitive() { + return false; + } + + /** + * Attaches a system-wide alias to this unit. Multiple aliases may be attached to the same unit. Aliases are used during parsing to recognize * different variants of the same unit. For example: SimpleUnitFormat.getInstance().alias(METER.multiply(0.3048), "foot"); * SimpleUnitFormat.getInstance().alias(METER.multiply(0.3048), "feet"); SimpleUnitFormat.getInstance().alias(METER, "meter"); - * SimpleUnitFormat.getInstance().alias(METER, "metre"); If the specified label is already associated to an unit the previous association is - * discarded or ignored. - * - * @param unit - * the unit being aliased. - * @param alias - * the alias attached to this unit. - * @throws IllegalArgumentException - * if the label is not a {@link SimpleUnitFormat#isValidIdentifier(String)} valid identifier. - */ - public abstract void alias(Unit unit, String alias); - - /** - * Indicates if the specified name can be used as unit identifier. - * - * @param name - * the identifier to be tested. - * @return true if the name specified can be used as label or alias for this format;false otherwise. - */ - public abstract boolean isValidIdentifier(String name); - - /** - * Formats an unit and appends the resulting text to a given string buffer (implements java.text.Format). - * - * @param unit - * the unit to format. - * @param toAppendTo - * where the text is to be appended - * @param pos - * the field position (not used). - * @return toAppendTo - */ - public final StringBuffer format(Object unit, final StringBuffer toAppendTo, FieldPosition pos) { - try { - Object dest = toAppendTo; - if (dest instanceof Appendable) { - format((Unit) unit, (Appendable) dest); - } else { // When retroweaver is used to produce 1.4 binaries. - format((Unit) unit, new Appendable() { - - public Appendable append(char arg0) throws IOException { - toAppendTo.append(arg0); - return null; - } - - public Appendable append(CharSequence arg0) throws IOException { - toAppendTo.append(arg0); - return null; - } - - public Appendable append(CharSequence arg0, int arg1, int arg2) throws IOException { - toAppendTo.append(arg0.subSequence(arg1, arg2)); - return null; - } - }); - } - return toAppendTo; - } catch (IOException e) { - throw new Error(e); // Should never happen. - } - } - - /** - * Parses the text from a string to produce an object (implements java.text.Format). - * - * @param source - * the string source, part of which should be parsed. - * @param pos - * the cursor position. - * @return the corresponding unit or null if the string cannot be parsed. - */ - public final Unit parseObject(String source, ParsePosition pos) throws ParserException { - // int start = pos.getIndex(); - return parseProductUnit(source, pos); - /* - * } catch (ParserException e) { pos.setIndex(start); - * pos.setErrorIndex(e.getPosition()); return null; } - */ - } - - /** - * This class represents an exponent with both a power (numerator) and a root (denominator). - */ - private static class Exponent { - public final int pow; - public final int root; - - public Exponent(int pow, int root) { - this.pow = pow; - this.root = root; - } - } - - /** - * This class represents the standard format. - */ - protected static class DefaultFormat extends SimpleUnitFormat { - - /** - * Holds the name to unit mapping. - */ - final HashMap> _nameToUnit = new HashMap<>(); - - /** - * Holds the unit to name mapping. - */ - final HashMap, String> _unitToName = new HashMap<>(); - - @Override - public void label(Unit unit, String label) { - if (!isValidIdentifier(label)) - throw new IllegalArgumentException("Label: " + label + " is not a valid identifier."); - synchronized (this) { - _nameToUnit.put(label, unit); - _unitToName.put(unit, label); - } - } - - @Override - public void alias(Unit unit, String alias) { - if (!isValidIdentifier(alias)) - throw new IllegalArgumentException("Alias: " + alias + " is not a valid identifier."); - synchronized (this) { - _nameToUnit.put(alias, unit); - } - } - - @Override - public boolean isValidIdentifier(String name) { - if ((name == null) || (name.length() == 0)) - return false; - /* - * for (int i = 0; i < name.length(); i++) { if - * (!isUnitIdentifierPart(name.charAt(i))) return false; } - */ - return isUnitIdentifierPart(name.charAt(0)); - } - - static boolean isUnitIdentifierPart(char ch) { - return Character.isLetter(ch) - || (!Character.isWhitespace(ch) && !Character.isDigit(ch) && (ch != '\u00b7') && (ch != '*') && (ch != '/') && (ch != '(') && (ch != ')') - && (ch != '[') && (ch != ']') && (ch != '\u00b9') && (ch != '\u00b2') && (ch != '\u00b3') && (ch != '^') && (ch != '+') && (ch != '-')); - } - - // Returns the name for the specified unit or null if product unit. - protected String nameFor(Unit unit) { - // Searches label database. - String label = _unitToName.get(unit); - if (label != null) - return label; - if (unit instanceof BaseUnit) - return ((BaseUnit) unit).getSymbol(); - if (unit instanceof AlternateUnit) - return ((AlternateUnit) unit).getSymbol(); - if (unit instanceof TransformedUnit) { - TransformedUnit tfmUnit = (TransformedUnit) unit; - Unit baseUnit = tfmUnit.getParentUnit(); - UnitConverter cvtr = tfmUnit.getConverter(); // tfmUnit.getSystemConverter(); - StringBuilder result = new StringBuilder(); - String baseUnitName = baseUnit.toString(); - String prefix = prefixFor(cvtr); - if ((baseUnitName.indexOf('\u00b7') >= 0) || (baseUnitName.indexOf('*') >= 0) || (baseUnitName.indexOf('/') >= 0)) { - // We could use parentheses whenever baseUnits is an - // instanceof ProductUnit, but most ProductUnits have - // aliases, - // so we'd end up with a lot of unnecessary parentheses. - result.append('('); - result.append(baseUnitName); - result.append(')'); - } else { - result.append(baseUnitName); - } - if (prefix != null) { - result.insert(0, prefix); - } else { - if (cvtr instanceof AddConverter) { - result.append('+'); - result.append(((AddConverter) cvtr).getOffset()); - } else if (cvtr instanceof RationalConverter) { - double dividend = ((RationalConverter) cvtr).getDividend().doubleValue(); - if (dividend != 1) { - result.append('*'); - result.append(dividend); - } - double divisor = ((RationalConverter) cvtr).getDivisor().doubleValue(); - if (divisor != 1) { - result.append('/'); - result.append(divisor); - } - } else if (cvtr instanceof MultiplyConverter) { - result.append('*'); - result.append(((MultiplyConverter) cvtr).getFactor()); - } else { // Other converters. - return "[" + baseUnit + "?]"; - } - } - return result.toString(); - } - // Compound unit. - // if (unit instanceof CompoundUnit) { - // CompoundUnit cpdUnit = (CompoundUnit) unit; - // return nameFor(cpdUnit.getHigher()).toString() + ":" - // + nameFor(cpdUnit.getLower()); - // } - return null; // Product unit. - } - - // Returns the prefix for the specified unit converter. - protected String prefixFor(UnitConverter converter) { - for (int i = 0; i < CONVERTERS.length; i++) { - if (CONVERTERS[i].equals(converter)) { - return PREFIXES[i]; - } - } - return null; // TODO or return blank? - } - - // Returns the unit for the specified name. - protected Unit unitFor(String name) { - Unit unit = _nameToUnit.get(name); - if (unit != null) - return unit; - unit = SYMBOL_TO_UNIT.get(name); - return unit; - } - - // ////////////////////////// - // Parsing. - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Unit parseSingleUnit(CharSequence csq, ParsePosition pos) throws ParserException { - int startIndex = pos.getIndex(); - String name = readIdentifier(csq, pos); - Unit unit = unitFor(name); - check(unit != null, name + " not recognized", csq, startIndex); - return unit; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public Unit parseProductUnit(CharSequence csq, ParsePosition pos) throws ParserException { - Unit result = AbstractUnit.ONE; - int token = nextToken(csq, pos); - switch (token) { - case IDENTIFIER: - result = parseSingleUnit(csq, pos); - break; - case OPEN_PAREN: - pos.setIndex(pos.getIndex() + 1); - result = parseProductUnit(csq, pos); - token = nextToken(csq, pos); - check(token == CLOSE_PAREN, "')' expected", csq, pos.getIndex()); - pos.setIndex(pos.getIndex() + 1); - break; - } - token = nextToken(csq, pos); - while (true) { - switch (token) { - case EXPONENT: - Exponent e = readExponent(csq, pos); - if (e.pow != 1) { - result = result.pow(e.pow); - } - if (e.root != 1) { - result = result.root(e.root); - } - break; - case MULTIPLY: - pos.setIndex(pos.getIndex() + 1); - token = nextToken(csq, pos); - if (token == INTEGER) { - long n = readLong(csq, pos); - if (n != 1) { - result = result.multiply(n); - } - } else if (token == FLOAT) { - double d = readDouble(csq, pos); - if (d != 1.0) { - result = result.multiply(d); - } - } else { - result = result.multiply(parseProductUnit(csq, pos)); - } - break; - case DIVIDE: - pos.setIndex(pos.getIndex() + 1); - token = nextToken(csq, pos); - if (token == INTEGER) { - long n = readLong(csq, pos); - if (n != 1) { - result = result.divide(n); - } - } else if (token == FLOAT) { - double d = readDouble(csq, pos); - if (d != 1.0) { - result = result.divide(d); - } - } else { - result = result.divide(parseProductUnit(csq, pos)); - } - break; - case PLUS: - pos.setIndex(pos.getIndex() + 1); - token = nextToken(csq, pos); - if (token == INTEGER) { - long n = readLong(csq, pos); - if (n != 1) { - result = result.shift(n); - } - } else if (token == FLOAT) { - double d = readDouble(csq, pos); - if (d != 1.0) { - result = result.shift(d); - } - } else { - throw new ParserException("not a number", pos.getIndex()); - } - break; - case EOF: - case CLOSE_PAREN: - return result; - default: - throw new ParserException("unexpected token " + token, pos.getIndex()); - } - token = nextToken(csq, pos); - } - } - - private static final int EOF = 0; - private static final int IDENTIFIER = 1; - private static final int OPEN_PAREN = 2; - private static final int CLOSE_PAREN = 3; - private static final int EXPONENT = 4; - private static final int MULTIPLY = 5; - private static final int DIVIDE = 6; - private static final int PLUS = 7; - private static final int INTEGER = 8; - private static final int FLOAT = 9; - - private int nextToken(CharSequence csq, ParsePosition pos) { - final int length = csq.length(); - while (pos.getIndex() < length) { - char c = csq.charAt(pos.getIndex()); - if (isUnitIdentifierPart(c)) { - return IDENTIFIER; - } else if (c == '(') { - return OPEN_PAREN; - } else if (c == ')') { - return CLOSE_PAREN; - } else if ((c == '^') || (c == '\u00b9') || (c == '\u00b2') || (c == '\u00b3')) { - return EXPONENT; - } else if (c == '*') { - char c2 = csq.charAt(pos.getIndex() + 1); - if (c2 == '*') { - return EXPONENT; - } else { - return MULTIPLY; - } - } else if (c == '\u00b7') { - return MULTIPLY; - } else if (c == '/') { - return DIVIDE; - } else if (c == '+') { - return PLUS; - } else if ((c == '-') || Character.isDigit(c)) { - int index = pos.getIndex() + 1; - while ((index < length) && (Character.isDigit(c) || (c == '-') || (c == '.') || (c == 'E'))) { - c = csq.charAt(index++); - if (c == '.') { - return FLOAT; - } - } - return INTEGER; - } - pos.setIndex(pos.getIndex() + 1); - } - return EOF; - } - - private void check(boolean expr, String message, CharSequence csq, int index) throws ParserException { - if (!expr) { - throw new ParserException(message + " (in " + csq + " at index " + index + ")", index); - } - } - - private Exponent readExponent(CharSequence csq, ParsePosition pos) { - char c = csq.charAt(pos.getIndex()); - if (c == '^') { - pos.setIndex(pos.getIndex() + 1); - } else if (c == '*') { - pos.setIndex(pos.getIndex() + 2); - } - final int length = csq.length(); - int pow = 0; - boolean isPowNegative = false; - int root = 0; - boolean isRootNegative = false; - boolean isRoot = false; - while (pos.getIndex() < length) { - c = csq.charAt(pos.getIndex()); - if (c == '\u00b9') { - if (isRoot) { - root = root * 10 + 1; - } else { - pow = pow * 10 + 1; - } - } else if (c == '\u00b2') { - if (isRoot) { - root = root * 10 + 2; - } else { - pow = pow * 10 + 2; - } - } else if (c == '\u00b3') { - if (isRoot) { - root = root * 10 + 3; - } else { - pow = pow * 10 + 3; - } - } else if (c == '-') { - if (isRoot) { - isRootNegative = true; - } else { - isPowNegative = true; - } - } else if ((c >= '0') && (c <= '9')) { - if (isRoot) { - root = root * 10 + (c - '0'); - } else { - pow = pow * 10 + (c - '0'); - } - } else if (c == ':') { - isRoot = true; - } else { - break; - } - pos.setIndex(pos.getIndex() + 1); - } - if (pow == 0) - pow = 1; - if (root == 0) - root = 1; - return new Exponent(isPowNegative ? -pow : pow, isRootNegative ? -root : root); - } - - private long readLong(CharSequence csq, ParsePosition pos) { - final int length = csq.length(); - int result = 0; - boolean isNegative = false; - while (pos.getIndex() < length) { - char c = csq.charAt(pos.getIndex()); - if (c == '-') { - isNegative = true; - } else if ((c >= '0') && (c <= '9')) { - result = result * 10 + (c - '0'); - } else { - break; - } - pos.setIndex(pos.getIndex() + 1); - } - return isNegative ? -result : result; - } - - private double readDouble(CharSequence csq, ParsePosition pos) { - final int length = csq.length(); - int start = pos.getIndex(); - int end = start + 1; - while (end < length) { - if ("0123456789+-.E".indexOf(csq.charAt(end)) < 0) { - break; - } - end += 1; - } - pos.setIndex(end + 1); - return Double.parseDouble(csq.subSequence(start, end).toString()); - } - - private String readIdentifier(CharSequence csq, ParsePosition pos) { - final int length = csq.length(); - int start = pos.getIndex(); - int i = start; - while ((++i < length) && isUnitIdentifierPart(csq.charAt(i))) { - } - pos.setIndex(i); - return csq.subSequence(start, i).toString(); - } - - // ////////////////////////// - // Formatting. - - @Override - public Appendable format(Unit unit, Appendable appendable) throws IOException { - String name = nameFor(unit); - if (name != null) { - return appendable.append(name); - } - if (!(unit instanceof ProductUnit)) { - throw new IllegalArgumentException("Cannot format given Object as a Unit"); - } - - // Product unit. - ProductUnit productUnit = (ProductUnit) unit; - int invNbr = 0; - - // Write positive exponents first. - boolean start = true; - for (int i = 0; i < productUnit.getUnitCount(); i++) { - int pow = productUnit.getUnitPow(i); - if (pow >= 0) { - if (!start) { - appendable.append('\u00b7'); // Separator. - } - name = nameFor(productUnit.getUnit(i)); - int root = productUnit.getUnitRoot(i); - append(appendable, name, pow, root); - start = false; - } else { - invNbr++; - } - } - - // Write negative exponents. - if (invNbr != 0) { - if (start) { - appendable.append('1'); // e.g. 1/s - } - appendable.append('/'); - if (invNbr > 1) { - appendable.append('('); - } - start = true; - for (int i = 0; i < productUnit.getUnitCount(); i++) { - int pow = productUnit.getUnitPow(i); - if (pow < 0) { - name = nameFor(productUnit.getUnit(i)); - int root = productUnit.getUnitRoot(i); - if (!start) { - appendable.append('\u00b7'); // Separator. - } - append(appendable, name, -pow, root); - start = false; - } - } - if (invNbr > 1) { - appendable.append(')'); - } - } - return appendable; - } - - private void append(Appendable appendable, CharSequence symbol, int pow, int root) throws IOException { - appendable.append(symbol); - if ((pow != 1) || (root != 1)) { - // Write exponent. - if ((pow == 2) && (root == 1)) { - appendable.append('\u00b2'); // Square - } else if ((pow == 3) && (root == 1)) { - appendable.append('\u00b3'); // Cubic - } else { - // Use general exponent form. - appendable.append('^'); - appendable.append(String.valueOf(pow)); - if (root != 1) { - appendable.append(':'); - appendable.append(String.valueOf(root)); - } - } - } - } - - // private static final long serialVersionUID = 1L; - - @Override - public Unit parse(CharSequence csq) throws ParserException { - return parse(csq, 0); - } - - @Override - protected SymbolMap getSymbols() { - return null; - } - - protected Unit parse(CharSequence csq, int index) throws IllegalArgumentException { - return parse(csq, new ParsePosition(index)); - } - - @Override - protected Unit parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException { - return parseObject(csq.toString(), cursor); - } - } - - /** - * This class represents the ASCII format. - */ - protected final static class ASCIIFormat extends DefaultFormat { - - @Override - protected String nameFor(Unit unit) { - // First search if specific ASCII name should be used. - String name = _unitToName.get(unit); - if (name != null) - return name; - // Else returns default name. - return DEFAULT.nameFor(unit); - } - - @Override - protected Unit unitFor(String name) { - // First search if specific ASCII name. - Unit unit = _nameToUnit.get(name); - if (unit != null) - return unit; - // Else returns default mapping. - return DEFAULT.unitFor(name); - } - - @Override - public Appendable format(Unit unit, Appendable appendable) throws IOException { - String name = nameFor(unit); - if (name != null) - return appendable.append(name); - if (!(unit instanceof ProductUnit)) - throw new IllegalArgumentException("Cannot format given Object as a Unit"); - - ProductUnit productUnit = (ProductUnit) unit; - for (int i = 0; i < productUnit.getUnitCount(); i++) { - if (i != 0) { - appendable.append('*'); // Separator. - } - name = nameFor(productUnit.getUnit(i)); - int pow = productUnit.getUnitPow(i); - int root = productUnit.getUnitRoot(i); - appendable.append(name); - if ((pow != 1) || (root != 1)) { - // Use general exponent form. - appendable.append('^'); - appendable.append(String.valueOf(pow)); - if (root != 1) { - appendable.append(':'); - appendable.append(String.valueOf(root)); - } - } - } - return appendable; - } - - @Override - public boolean isValidIdentifier(String name) { - if ((name == null) || (name.length() == 0)) - return false; - // label must not begin with a digit or mathematical operator - return isUnitIdentifierPart(name.charAt(0)) && isAllASCII(name); - /* - * for (int i = 0; i < name.length(); i++) { if - * (!isAsciiCharacter(name.charAt(i))) return false; } return true; - */ - } - } - - /** - * Holds the unique symbols collection (base units or alternate units). - */ - private static final Map> SYMBOL_TO_UNIT = new HashMap<>(); - - // ////////////////////////////////////////////////////////////////////////// - // Initializes the standard unit database for SI units. - - private static final Unit[] SI_UNITS = { Units.AMPERE, Units.BECQUEREL, Units.CANDELA, Units.COULOMB, Units.FARAD, Units.GRAY, Units.HENRY, - Units.HERTZ, Units.JOULE, Units.KATAL, Units.KELVIN, Units.LUMEN, Units.LUX, Units.METRE, Units.MOLE, Units.NEWTON, Units.OHM, Units.PASCAL, - Units.RADIAN, Units.SECOND, Units.SIEMENS, Units.SIEVERT, Units.STERADIAN, Units.TESLA, Units.VOLT, Units.WATT, Units.WEBER }; - - private static final String[] PREFIXES = { YOTTA.getSymbol(), ZETTA.getSymbol(), EXA.getSymbol(), PETA.getSymbol(), TERA.getSymbol(), - GIGA.getSymbol(), MEGA.getSymbol(), KILO.getSymbol(), HECTO.getSymbol(), DEKA.getSymbol(), DECI.getSymbol(), CENTI.getSymbol(), - MILLI.getSymbol(), MICRO.getSymbol(), NANO.getSymbol(), PICO.getSymbol(), FEMTO.getSymbol(), ATTO.getSymbol(), ZEPTO.getSymbol(), - YOCTO.getSymbol() }; - - // TODO we could try retrieving this dynamically in a static {} method from - // MetricPrefix if symbols above are also aligned - private static final UnitConverter[] CONVERTERS = { YOTTA.getConverter(), ZETTA.getConverter(), EXA.getConverter(), PETA.getConverter(), - TERA.getConverter(), GIGA.getConverter(), MEGA.getConverter(), KILO.getConverter(), HECTO.getConverter(), DEKA.getConverter(), - DECI.getConverter(), CENTI.getConverter(), MILLI.getConverter(), MICRO.getConverter(), NANO.getConverter(), PICO.getConverter(), - FEMTO.getConverter(), ATTO.getConverter(), ZEPTO.getConverter(), YOCTO.getConverter() }; - - private static String asciiPrefix(String prefix) { - return prefix == "µ" ? "micro" : prefix; - } - - // to check if a string only contains US-ASCII characters - // - protected static boolean isAllASCII(String input) { - boolean isASCII = true; - for (int i = 0; i < input.length(); i++) { - int c = input.charAt(i); - if (c > 0x7F) { - isASCII = false; - break; - } - } - return isASCII; - } - - // Initializations - static { - for (int i = 0; i < SI_UNITS.length; i++) { - Unit si = SI_UNITS[i]; - String symbol = (si instanceof BaseUnit) ? ((BaseUnit) si).getSymbol() : ((AlternateUnit) si).getSymbol(); - DEFAULT.label(si, symbol); - if (isAllASCII(symbol)) - ASCII.label(si, symbol); - for (int j = 0; j < PREFIXES.length; j++) { - Unit u = si.transform(CONVERTERS[j]); - DEFAULT.label(u, PREFIXES[j] + symbol); - if (PREFIXES[j] == "µ") { - ASCII.label(u, "micro"); // + symbol); - } - } - } - // Special case for KILOGRAM. - DEFAULT.label(Units.GRAM, "g"); - for (int i = 0; i < PREFIXES.length; i++) { - if (CONVERTERS[i] == KILO.getConverter()) // TODO should it better - // be equals()? - continue; // kg is already defined. - DEFAULT.label(Units.KILOGRAM.transform(CONVERTERS[i].concatenate(MILLI.getConverter())), PREFIXES[i] + "g"); - if (PREFIXES[i] == "µ") { - ASCII.label(Units.KILOGRAM.transform(CONVERTERS[i].concatenate(MILLI.getConverter())), "microg"); - } - } - - // Alias and ASCIIFormat for Ohm - DEFAULT.alias(Units.OHM, "Ohm"); - ASCII.label(Units.OHM, "Ohm"); - for (int i = 0; i < PREFIXES.length; i++) { - DEFAULT.alias(Units.OHM.transform(CONVERTERS[i]), PREFIXES[i] + "Ohm"); - ASCII.label(Units.OHM.transform(CONVERTERS[i]), asciiPrefix(PREFIXES[i]) + "Ohm"); - } - - // Special case for DEGREE_CELSIUS. - DEFAULT.label(Units.CELSIUS, "℃"); - DEFAULT.alias(Units.CELSIUS, "°C"); - ASCII.label(Units.CELSIUS, "Celsius"); - for (int i = 0; i < PREFIXES.length; i++) { - DEFAULT.label(Units.CELSIUS.transform(CONVERTERS[i]), PREFIXES[i] + "℃"); - DEFAULT.alias(Units.CELSIUS.transform(CONVERTERS[i]), PREFIXES[i] + "°C"); - ASCII.label(Units.CELSIUS.transform(CONVERTERS[i]), asciiPrefix(PREFIXES[i]) + "Celsius"); - } - - DEFAULT.label(Units.PERCENT, "%"); - DEFAULT.label(Units.KILOGRAM, "kg"); - ASCII.label(Units.KILOGRAM, "kg"); - DEFAULT.label(Units.METRE, "m"); - ASCII.label(Units.METRE, "m"); - DEFAULT.label(Units.SECOND, "s"); - ASCII.label(Units.SECOND, "s"); - DEFAULT.label(Units.MINUTE, "min"); - DEFAULT.label(Units.HOUR, "h"); - DEFAULT.label(Units.DAY, "day"); - DEFAULT.alias(Units.DAY, "d"); - DEFAULT.label(Units.WEEK, "week"); - DEFAULT.label(Units.YEAR, "year"); - DEFAULT.alias(Units.YEAR, "days365"); - ASCII.label(Units.KILOMETRE_PER_HOUR, "km/h"); - DEFAULT.label(Units.KILOMETRE_PER_HOUR, "km/h"); - DEFAULT.label(Units.CUBIC_METRE, "\u33A5"); - ASCII.label(Units.CUBIC_METRE, "m3"); - ASCII.label(Units.LITRE, "l"); - DEFAULT.label(Units.LITRE, "l"); - DEFAULT.label(MetricPrefix.MICRO(Units.LITRE), "µl"); - ASCII.label(MetricPrefix.MICRO(Units.LITRE), "microL"); - ASCII.label(MetricPrefix.MILLI(Units.LITRE), "mL"); - DEFAULT.label(MetricPrefix.MILLI(Units.LITRE), "ml"); - ASCII.label(MetricPrefix.CENTI(Units.LITRE), "cL"); - DEFAULT.label(MetricPrefix.CENTI(Units.LITRE), "cl"); - ASCII.label(MetricPrefix.DECI(Units.LITRE), "dL"); - DEFAULT.label(MetricPrefix.DECI(Units.LITRE), "dl"); - DEFAULT.label(Units.NEWTON, "N"); - ASCII.label(Units.NEWTON, "N"); - DEFAULT.label(Units.RADIAN, "rad"); - ASCII.label(Units.RADIAN, "rad"); - - DEFAULT.label(AbstractUnit.ONE, "one"); - ASCII.label(AbstractUnit.ONE, "one"); - } -} + * SimpleUnitFormat.getInstance().alias(METER, "metre"); If the specified label is already associated to an unit the previous association is + * discarded or ignored. + * + * @param unit + * the unit being aliased. + * @param alias + * the alias attached to this unit. + * @throws IllegalArgumentException + * if the label is not a {@link SimpleUnitFormat#isValidIdentifier(String)} valid identifier. + */ + public abstract void alias(Unit unit, String alias); + + /** + * Indicates if the specified name can be used as unit identifier. + * + * @param name + * the identifier to be tested. + * @return true if the name specified can be used as label or alias for this format;false otherwise. + */ + public abstract boolean isValidIdentifier(String name); + + /** + * Formats an unit and appends the resulting text to a given string buffer (implements java.text.Format). + * + * @param unit + * the unit to format. + * @param toAppendTo + * where the text is to be appended + * @param pos + * the field position (not used). + * @return toAppendTo + */ + public final StringBuffer format(Object unit, final StringBuffer toAppendTo, FieldPosition pos) { + try { + Object dest = toAppendTo; + if (dest instanceof Appendable) { + format((Unit) unit, (Appendable) dest); + } else { // When retroweaver is used to produce 1.4 binaries. + format((Unit) unit, new Appendable() { + + public Appendable append(char arg0) throws IOException { + toAppendTo.append(arg0); + return null; + } + + public Appendable append(CharSequence arg0) throws IOException { + toAppendTo.append(arg0); + return null; + } + + public Appendable append(CharSequence arg0, int arg1, int arg2) throws IOException { + toAppendTo.append(arg0.subSequence(arg1, arg2)); + return null; + } + }); + } + return toAppendTo; + } catch (IOException e) { + throw new Error(e); // Should never happen. + } + } + + /** + * Parses the text from a string to produce an object (implements java.text.Format). + * + * @param source + * the string source, part of which should be parsed. + * @param pos + * the cursor position. + * @return the corresponding unit or null if the string cannot be parsed. + */ + public final Unit parseObject(String source, ParsePosition pos) throws ParserException { + // int start = pos.getIndex(); + return parseProductUnit(source, pos); + /* + * } catch (ParserException e) { pos.setIndex(start); + * pos.setErrorIndex(e.getPosition()); return null; } + */ + } + + /** + * This class represents an exponent with both a power (numerator) and a root (denominator). + */ + private static class Exponent { + public final int pow; + public final int root; + + public Exponent(int pow, int root) { + this.pow = pow; + this.root = root; + } + } + + /** + * This class represents the standard format. + */ + protected static class DefaultFormat extends SimpleUnitFormat { + + /** + * Holds the name to unit mapping. + */ + final HashMap> _nameToUnit = new HashMap<>(); + + /** + * Holds the unit to name mapping. + */ + final HashMap, String> _unitToName = new HashMap<>(); + + @Override + public void label(Unit unit, String label) { + if (!isValidIdentifier(label)) + throw new IllegalArgumentException("Label: " + label + " is not a valid identifier."); + synchronized (this) { + _nameToUnit.put(label, unit); + _unitToName.put(unit, label); + } + } + + @Override + public void alias(Unit unit, String alias) { + if (!isValidIdentifier(alias)) + throw new IllegalArgumentException("Alias: " + alias + " is not a valid identifier."); + synchronized (this) { + _nameToUnit.put(alias, unit); + } + } + + @Override + public boolean isValidIdentifier(String name) { + if ((name == null) || (name.length() == 0)) + return false; + /* + * for (int i = 0; i < name.length(); i++) { if + * (!isUnitIdentifierPart(name.charAt(i))) return false; } + */ + return isUnitIdentifierPart(name.charAt(0)); + } + + static boolean isUnitIdentifierPart(char ch) { + return Character.isLetter(ch) + || (!Character.isWhitespace(ch) && !Character.isDigit(ch) && (ch != '\u00b7') && (ch != '*') && (ch != '/') && (ch != '(') && (ch != ')') + && (ch != '[') && (ch != ']') && (ch != '\u00b9') && (ch != '\u00b2') && (ch != '\u00b3') && (ch != '^') && (ch != '+') && (ch != '-')); + } + + // Returns the name for the specified unit or null if product unit. + protected String nameFor(Unit unit) { + // Searches label database. + String label = _unitToName.get(unit); + if (label != null) + return label; + if (unit instanceof BaseUnit) + return ((BaseUnit) unit).getSymbol(); + if (unit instanceof AlternateUnit) + return ((AlternateUnit) unit).getSymbol(); + if (unit instanceof TransformedUnit) { + TransformedUnit tfmUnit = (TransformedUnit) unit; + Unit baseUnit = tfmUnit.getParentUnit(); + UnitConverter cvtr = tfmUnit.getConverter(); // tfmUnit.getSystemConverter(); + StringBuilder result = new StringBuilder(); + String baseUnitName = baseUnit.toString(); + String prefix = prefixFor(cvtr); + if ((baseUnitName.indexOf('\u00b7') >= 0) || (baseUnitName.indexOf('*') >= 0) || (baseUnitName.indexOf('/') >= 0)) { + // We could use parentheses whenever baseUnits is an + // instanceof ProductUnit, but most ProductUnits have + // aliases, + // so we'd end up with a lot of unnecessary parentheses. + result.append('('); + result.append(baseUnitName); + result.append(')'); + } else { + result.append(baseUnitName); + } + if (prefix != null) { + result.insert(0, prefix); + } else { + if (cvtr instanceof AddConverter) { + result.append('+'); + result.append(((AddConverter) cvtr).getOffset()); + } else if (cvtr instanceof RationalConverter) { + double dividend = ((RationalConverter) cvtr).getDividend().doubleValue(); + if (dividend != 1) { + result.append('*'); + result.append(dividend); + } + double divisor = ((RationalConverter) cvtr).getDivisor().doubleValue(); + if (divisor != 1) { + result.append('/'); + result.append(divisor); + } + } else if (cvtr instanceof MultiplyConverter) { + result.append('*'); + result.append(((MultiplyConverter) cvtr).getFactor()); + } else { // Other converters. + return "[" + baseUnit + "?]"; + } + } + return result.toString(); + } + // Compound unit. + // if (unit instanceof CompoundUnit) { + // CompoundUnit cpdUnit = (CompoundUnit) unit; + // return nameFor(cpdUnit.getHigher()).toString() + ":" + // + nameFor(cpdUnit.getLower()); + // } + return null; // Product unit. + } + + // Returns the prefix for the specified unit converter. + protected String prefixFor(UnitConverter converter) { + for (int i = 0; i < CONVERTERS.length; i++) { + if (CONVERTERS[i].equals(converter)) { + return PREFIXES[i]; + } + } + return null; // TODO or return blank? + } + + // Returns the unit for the specified name. + protected Unit unitFor(String name) { + Unit unit = _nameToUnit.get(name); + if (unit != null) + return unit; + unit = SYMBOL_TO_UNIT.get(name); + return unit; + } + + // ////////////////////////// + // Parsing. + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Unit parseSingleUnit(CharSequence csq, ParsePosition pos) throws ParserException { + int startIndex = pos.getIndex(); + String name = readIdentifier(csq, pos); + Unit unit = unitFor(name); + check(unit != null, name + " not recognized", csq, startIndex); + return unit; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Unit parseProductUnit(CharSequence csq, ParsePosition pos) throws ParserException { + Unit result = AbstractUnit.ONE; + int token = nextToken(csq, pos); + switch (token) { + case IDENTIFIER: + result = parseSingleUnit(csq, pos); + break; + case OPEN_PAREN: + pos.setIndex(pos.getIndex() + 1); + result = parseProductUnit(csq, pos); + token = nextToken(csq, pos); + check(token == CLOSE_PAREN, "')' expected", csq, pos.getIndex()); + pos.setIndex(pos.getIndex() + 1); + break; + } + token = nextToken(csq, pos); + while (true) { + switch (token) { + case EXPONENT: + Exponent e = readExponent(csq, pos); + if (e.pow != 1) { + result = result.pow(e.pow); + } + if (e.root != 1) { + result = result.root(e.root); + } + break; + case MULTIPLY: + pos.setIndex(pos.getIndex() + 1); + token = nextToken(csq, pos); + if (token == INTEGER) { + long n = readLong(csq, pos); + if (n != 1) { + result = result.multiply(n); + } + } else if (token == FLOAT) { + double d = readDouble(csq, pos); + if (d != 1.0) { + result = result.multiply(d); + } + } else { + result = result.multiply(parseProductUnit(csq, pos)); + } + break; + case DIVIDE: + pos.setIndex(pos.getIndex() + 1); + token = nextToken(csq, pos); + if (token == INTEGER) { + long n = readLong(csq, pos); + if (n != 1) { + result = result.divide(n); + } + } else if (token == FLOAT) { + double d = readDouble(csq, pos); + if (d != 1.0) { + result = result.divide(d); + } + } else { + result = result.divide(parseProductUnit(csq, pos)); + } + break; + case PLUS: + pos.setIndex(pos.getIndex() + 1); + token = nextToken(csq, pos); + if (token == INTEGER) { + long n = readLong(csq, pos); + if (n != 1) { + result = result.shift(n); + } + } else if (token == FLOAT) { + double d = readDouble(csq, pos); + if (d != 1.0) { + result = result.shift(d); + } + } else { + throw new ParserException("not a number", pos.getIndex()); + } + break; + case EOF: + case CLOSE_PAREN: + return result; + default: + throw new ParserException("unexpected token " + token, pos.getIndex()); + } + token = nextToken(csq, pos); + } + } + + private static final int EOF = 0; + private static final int IDENTIFIER = 1; + private static final int OPEN_PAREN = 2; + private static final int CLOSE_PAREN = 3; + private static final int EXPONENT = 4; + private static final int MULTIPLY = 5; + private static final int DIVIDE = 6; + private static final int PLUS = 7; + private static final int INTEGER = 8; + private static final int FLOAT = 9; + + private int nextToken(CharSequence csq, ParsePosition pos) { + final int length = csq.length(); + while (pos.getIndex() < length) { + char c = csq.charAt(pos.getIndex()); + if (isUnitIdentifierPart(c)) { + return IDENTIFIER; + } else if (c == '(') { + return OPEN_PAREN; + } else if (c == ')') { + return CLOSE_PAREN; + } else if ((c == '^') || (c == '\u00b9') || (c == '\u00b2') || (c == '\u00b3')) { + return EXPONENT; + } else if (c == '*') { + char c2 = csq.charAt(pos.getIndex() + 1); + if (c2 == '*') { + return EXPONENT; + } else { + return MULTIPLY; + } + } else if (c == '\u00b7') { + return MULTIPLY; + } else if (c == '/') { + return DIVIDE; + } else if (c == '+') { + return PLUS; + } else if ((c == '-') || Character.isDigit(c)) { + int index = pos.getIndex() + 1; + while ((index < length) && (Character.isDigit(c) || (c == '-') || (c == '.') || (c == 'E'))) { + c = csq.charAt(index++); + if (c == '.') { + return FLOAT; + } + } + return INTEGER; + } + pos.setIndex(pos.getIndex() + 1); + } + return EOF; + } + + private void check(boolean expr, String message, CharSequence csq, int index) throws ParserException { + if (!expr) { + throw new ParserException(message + " (in " + csq + " at index " + index + ")", index); + } + } + + private Exponent readExponent(CharSequence csq, ParsePosition pos) { + char c = csq.charAt(pos.getIndex()); + if (c == '^') { + pos.setIndex(pos.getIndex() + 1); + } else if (c == '*') { + pos.setIndex(pos.getIndex() + 2); + } + final int length = csq.length(); + int pow = 0; + boolean isPowNegative = false; + int root = 0; + boolean isRootNegative = false; + boolean isRoot = false; + while (pos.getIndex() < length) { + c = csq.charAt(pos.getIndex()); + if (c == '\u00b9') { + if (isRoot) { + root = root * 10 + 1; + } else { + pow = pow * 10 + 1; + } + } else if (c == '\u00b2') { + if (isRoot) { + root = root * 10 + 2; + } else { + pow = pow * 10 + 2; + } + } else if (c == '\u00b3') { + if (isRoot) { + root = root * 10 + 3; + } else { + pow = pow * 10 + 3; + } + } else if (c == '-') { + if (isRoot) { + isRootNegative = true; + } else { + isPowNegative = true; + } + } else if ((c >= '0') && (c <= '9')) { + if (isRoot) { + root = root * 10 + (c - '0'); + } else { + pow = pow * 10 + (c - '0'); + } + } else if (c == ':') { + isRoot = true; + } else { + break; + } + pos.setIndex(pos.getIndex() + 1); + } + if (pow == 0) + pow = 1; + if (root == 0) + root = 1; + return new Exponent(isPowNegative ? -pow : pow, isRootNegative ? -root : root); + } + + private long readLong(CharSequence csq, ParsePosition pos) { + final int length = csq.length(); + int result = 0; + boolean isNegative = false; + while (pos.getIndex() < length) { + char c = csq.charAt(pos.getIndex()); + if (c == '-') { + isNegative = true; + } else if ((c >= '0') && (c <= '9')) { + result = result * 10 + (c - '0'); + } else { + break; + } + pos.setIndex(pos.getIndex() + 1); + } + return isNegative ? -result : result; + } + + private double readDouble(CharSequence csq, ParsePosition pos) { + final int length = csq.length(); + int start = pos.getIndex(); + int end = start + 1; + while (end < length) { + if ("0123456789+-.E".indexOf(csq.charAt(end)) < 0) { + break; + } + end += 1; + } + pos.setIndex(end + 1); + return Double.parseDouble(csq.subSequence(start, end).toString()); + } + + private String readIdentifier(CharSequence csq, ParsePosition pos) { + final int length = csq.length(); + int start = pos.getIndex(); + int i = start; + while ((++i < length) && isUnitIdentifierPart(csq.charAt(i))) { + } + pos.setIndex(i); + return csq.subSequence(start, i).toString(); + } + + // ////////////////////////// + // Formatting. + + @Override + public Appendable format(Unit unit, Appendable appendable) throws IOException { + String name = nameFor(unit); + if (name != null) { + return appendable.append(name); + } + if (!(unit instanceof ProductUnit)) { + throw new IllegalArgumentException("Cannot format given Object as a Unit"); + } + + // Product unit. + ProductUnit productUnit = (ProductUnit) unit; + int invNbr = 0; + + // Write positive exponents first. + boolean start = true; + for (int i = 0; i < productUnit.getUnitCount(); i++) { + int pow = productUnit.getUnitPow(i); + if (pow >= 0) { + if (!start) { + appendable.append('\u00b7'); // Separator. + } + name = nameFor(productUnit.getUnit(i)); + int root = productUnit.getUnitRoot(i); + append(appendable, name, pow, root); + start = false; + } else { + invNbr++; + } + } + + // Write negative exponents. + if (invNbr != 0) { + if (start) { + appendable.append('1'); // e.g. 1/s + } + appendable.append('/'); + if (invNbr > 1) { + appendable.append('('); + } + start = true; + for (int i = 0; i < productUnit.getUnitCount(); i++) { + int pow = productUnit.getUnitPow(i); + if (pow < 0) { + name = nameFor(productUnit.getUnit(i)); + int root = productUnit.getUnitRoot(i); + if (!start) { + appendable.append('\u00b7'); // Separator. + } + append(appendable, name, -pow, root); + start = false; + } + } + if (invNbr > 1) { + appendable.append(')'); + } + } + return appendable; + } + + private void append(Appendable appendable, CharSequence symbol, int pow, int root) throws IOException { + appendable.append(symbol); + if ((pow != 1) || (root != 1)) { + // Write exponent. + if ((pow == 2) && (root == 1)) { + appendable.append('\u00b2'); // Square + } else if ((pow == 3) && (root == 1)) { + appendable.append('\u00b3'); // Cubic + } else { + // Use general exponent form. + appendable.append('^'); + appendable.append(String.valueOf(pow)); + if (root != 1) { + appendable.append(':'); + appendable.append(String.valueOf(root)); + } + } + } + } + + // private static final long serialVersionUID = 1L; + + @Override + public Unit parse(CharSequence csq) throws ParserException { + return parse(csq, 0); + } + + @Override + protected SymbolMap getSymbols() { + return null; + } + + protected Unit parse(CharSequence csq, int index) throws IllegalArgumentException { + return parse(csq, new ParsePosition(index)); + } + + @Override + protected Unit parse(CharSequence csq, ParsePosition cursor) throws IllegalArgumentException { + return parseObject(csq.toString(), cursor); + } + } + + /** + * This class represents the ASCII format. + */ + protected final static class ASCIIFormat extends DefaultFormat { + + @Override + protected String nameFor(Unit unit) { + // First search if specific ASCII name should be used. + String name = _unitToName.get(unit); + if (name != null) + return name; + // Else returns default name. + return DEFAULT.nameFor(unit); + } + + @Override + protected Unit unitFor(String name) { + // First search if specific ASCII name. + Unit unit = _nameToUnit.get(name); + if (unit != null) + return unit; + // Else returns default mapping. + return DEFAULT.unitFor(name); + } + + @Override + public Appendable format(Unit unit, Appendable appendable) throws IOException { + String name = nameFor(unit); + if (name != null) + return appendable.append(name); + if (!(unit instanceof ProductUnit)) + throw new IllegalArgumentException("Cannot format given Object as a Unit"); + + ProductUnit productUnit = (ProductUnit) unit; + for (int i = 0; i < productUnit.getUnitCount(); i++) { + if (i != 0) { + appendable.append('*'); // Separator. + } + name = nameFor(productUnit.getUnit(i)); + int pow = productUnit.getUnitPow(i); + int root = productUnit.getUnitRoot(i); + appendable.append(name); + if ((pow != 1) || (root != 1)) { + // Use general exponent form. + appendable.append('^'); + appendable.append(String.valueOf(pow)); + if (root != 1) { + appendable.append(':'); + appendable.append(String.valueOf(root)); + } + } + } + return appendable; + } + + @Override + public boolean isValidIdentifier(String name) { + if ((name == null) || (name.length() == 0)) + return false; + // label must not begin with a digit or mathematical operator + return isUnitIdentifierPart(name.charAt(0)) && isAllASCII(name); + /* + * for (int i = 0; i < name.length(); i++) { if + * (!isAsciiCharacter(name.charAt(i))) return false; } return true; + */ + } + } + + /** + * Holds the unique symbols collection (base units or alternate units). + */ + private static final Map> SYMBOL_TO_UNIT = new HashMap<>(); + + // ////////////////////////////////////////////////////////////////////////// + // Initializes the standard unit database for SI units. + + private static final Unit[] SI_UNITS = { Units.AMPERE, Units.BECQUEREL, Units.CANDELA, Units.COULOMB, Units.FARAD, Units.GRAY, Units.HENRY, + Units.HERTZ, Units.JOULE, Units.KATAL, Units.KELVIN, Units.LUMEN, Units.LUX, Units.METRE, Units.MOLE, Units.NEWTON, Units.OHM, Units.PASCAL, + Units.RADIAN, Units.SECOND, Units.SIEMENS, Units.SIEVERT, Units.STERADIAN, Units.TESLA, Units.VOLT, Units.WATT, Units.WEBER }; + + private static final String[] PREFIXES = { YOTTA.getSymbol(), ZETTA.getSymbol(), EXA.getSymbol(), PETA.getSymbol(), TERA.getSymbol(), + GIGA.getSymbol(), MEGA.getSymbol(), KILO.getSymbol(), HECTO.getSymbol(), DEKA.getSymbol(), DECI.getSymbol(), CENTI.getSymbol(), + MILLI.getSymbol(), MICRO.getSymbol(), NANO.getSymbol(), PICO.getSymbol(), FEMTO.getSymbol(), ATTO.getSymbol(), ZEPTO.getSymbol(), + YOCTO.getSymbol() }; + + // TODO we could try retrieving this dynamically in a static {} method from + // MetricPrefix if symbols above are also aligned + private static final UnitConverter[] CONVERTERS = { YOTTA.getConverter(), ZETTA.getConverter(), EXA.getConverter(), PETA.getConverter(), + TERA.getConverter(), GIGA.getConverter(), MEGA.getConverter(), KILO.getConverter(), HECTO.getConverter(), DEKA.getConverter(), + DECI.getConverter(), CENTI.getConverter(), MILLI.getConverter(), MICRO.getConverter(), NANO.getConverter(), PICO.getConverter(), + FEMTO.getConverter(), ATTO.getConverter(), ZEPTO.getConverter(), YOCTO.getConverter() }; + + private static String asciiPrefix(String prefix) { + return prefix == "µ" ? "micro" : prefix; + } + + // to check if a string only contains US-ASCII characters + // + protected static boolean isAllASCII(String input) { + boolean isASCII = true; + for (int i = 0; i < input.length(); i++) { + int c = input.charAt(i); + if (c > 0x7F) { + isASCII = false; + break; + } + } + return isASCII; + } + + // Initializations + static { + for (int i = 0; i < SI_UNITS.length; i++) { + Unit si = SI_UNITS[i]; + String symbol = (si instanceof BaseUnit) ? ((BaseUnit) si).getSymbol() : ((AlternateUnit) si).getSymbol(); + DEFAULT.label(si, symbol); + if (isAllASCII(symbol)) + ASCII.label(si, symbol); + for (int j = 0; j < PREFIXES.length; j++) { + Unit u = si.transform(CONVERTERS[j]); + DEFAULT.label(u, PREFIXES[j] + symbol); + if (PREFIXES[j] == "µ") { + ASCII.label(u, "micro"); // + symbol); + } + } + } + // Special case for KILOGRAM. + DEFAULT.label(Units.GRAM, "g"); + for (int i = 0; i < PREFIXES.length; i++) { + if (CONVERTERS[i] == KILO.getConverter()) // TODO should it better + // be equals()? + continue; // kg is already defined. + DEFAULT.label(Units.KILOGRAM.transform(CONVERTERS[i].concatenate(MILLI.getConverter())), PREFIXES[i] + "g"); + if (PREFIXES[i] == "µ") { + ASCII.label(Units.KILOGRAM.transform(CONVERTERS[i].concatenate(MILLI.getConverter())), "microg"); + } + } + + // Alias and ASCIIFormat for Ohm + DEFAULT.alias(Units.OHM, "Ohm"); + ASCII.label(Units.OHM, "Ohm"); + for (int i = 0; i < PREFIXES.length; i++) { + DEFAULT.alias(Units.OHM.transform(CONVERTERS[i]), PREFIXES[i] + "Ohm"); + ASCII.label(Units.OHM.transform(CONVERTERS[i]), asciiPrefix(PREFIXES[i]) + "Ohm"); + } + + // Special case for DEGREE_CELSIUS. + DEFAULT.label(Units.CELSIUS, "℃"); + DEFAULT.alias(Units.CELSIUS, "°C"); + ASCII.label(Units.CELSIUS, "Celsius"); + for (int i = 0; i < PREFIXES.length; i++) { + DEFAULT.label(Units.CELSIUS.transform(CONVERTERS[i]), PREFIXES[i] + "℃"); + DEFAULT.alias(Units.CELSIUS.transform(CONVERTERS[i]), PREFIXES[i] + "°C"); + ASCII.label(Units.CELSIUS.transform(CONVERTERS[i]), asciiPrefix(PREFIXES[i]) + "Celsius"); + } + + DEFAULT.label(Units.PERCENT, "%"); + DEFAULT.label(Units.KILOGRAM, "kg"); + ASCII.label(Units.KILOGRAM, "kg"); + DEFAULT.label(Units.METRE, "m"); + ASCII.label(Units.METRE, "m"); + DEFAULT.label(Units.SECOND, "s"); + ASCII.label(Units.SECOND, "s"); + DEFAULT.label(Units.MINUTE, "min"); + DEFAULT.label(Units.HOUR, "h"); + DEFAULT.label(Units.DAY, "day"); + DEFAULT.alias(Units.DAY, "d"); + DEFAULT.label(Units.WEEK, "week"); + DEFAULT.label(Units.YEAR, "year"); + DEFAULT.alias(Units.YEAR, "days365"); + ASCII.label(Units.KILOMETRE_PER_HOUR, "km/h"); + DEFAULT.label(Units.KILOMETRE_PER_HOUR, "km/h"); + DEFAULT.label(Units.CUBIC_METRE, "\u33A5"); + ASCII.label(Units.CUBIC_METRE, "m3"); + ASCII.label(Units.LITRE, "l"); + DEFAULT.label(Units.LITRE, "l"); + DEFAULT.label(MetricPrefix.MICRO(Units.LITRE), "µl"); + ASCII.label(MetricPrefix.MICRO(Units.LITRE), "microL"); + ASCII.label(MetricPrefix.MILLI(Units.LITRE), "mL"); + DEFAULT.label(MetricPrefix.MILLI(Units.LITRE), "ml"); + ASCII.label(MetricPrefix.CENTI(Units.LITRE), "cL"); + DEFAULT.label(MetricPrefix.CENTI(Units.LITRE), "cl"); + ASCII.label(MetricPrefix.DECI(Units.LITRE), "dL"); + DEFAULT.label(MetricPrefix.DECI(Units.LITRE), "dl"); + DEFAULT.label(Units.NEWTON, "N"); + ASCII.label(Units.NEWTON, "N"); + DEFAULT.label(Units.RADIAN, "rad"); + ASCII.label(Units.RADIAN, "rad"); + + DEFAULT.label(AbstractUnit.ONE, "one"); + ASCII.label(AbstractUnit.ONE, "one"); + } +} diff --git a/src/main/java/tec/uom/se/format/SymbolMap.java b/src/main/java/tec/uom/se/format/SymbolMap.java index 3c8e475c..23b5ac0d 100644 --- a/src/main/java/tec/uom/se/format/SymbolMap.java +++ b/src/main/java/tec/uom/se/format/SymbolMap.java @@ -1,216 +1,216 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -import tec.uom.se.AbstractConverter; -import tec.uom.se.AbstractUnit; -import tec.uom.se.unit.MetricPrefix; - -import javax.measure.Unit; -import javax.measure.UnitConverter; - -import java.lang.reflect.Field; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ResourceBundle; -import java.util.TreeMap; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - *

- * This class provides a set of mappings between {@link AbstractUnit units} and symbols (both ways), between {@link MetricPrefix prefixes} and symbols - * (both ways), and from {@link AbstractConverter unit converters} to {@link MetricPrefix prefixes} (one way). No attempt is made to verify the - * uniqueness of the mappings. - *

- * - *

- * Mappings are read from a ResourceBundle, the keys of which should consist of a fully-qualified class name, followed by a dot ('.'), - * and then the name of a static field belonging to that class, followed optionally by another dot and a number. If the trailing dot and number are - * not present, the value associated with the key is treated as a {@link SymbolMap#label(AbstractUnit, String) label}, otherwise if the trailing dot - * and number are present, the value is treated as an {@link SymbolMap#alias(AbstractUnit,String) alias}. Aliases map from String to Unit only, - * whereas labels map in both directions. A given unit may have any number of aliases, but may have only one label. - *

- * - * @author Eric Russell - * @author Werner Keil - * @version 1.7, February 25, 2017 - */ -@SuppressWarnings("rawtypes") -public final class SymbolMap { - private static final Logger logger = Logger.getLogger(SymbolMap.class.getName()); - - private final Map> symbolToUnit; - private final Map, String> unitToSymbol; - private final Map symbolToPrefix; - private final Map prefixToSymbol; - private final Map converterToPrefix; - - /** - * Creates an empty mapping. - */ - private SymbolMap() { - symbolToUnit = new TreeMap<>(); - unitToSymbol = new HashMap<>(); - symbolToPrefix = new TreeMap<>(); - prefixToSymbol = new HashMap<>(); - converterToPrefix = new HashMap<>(); - } - - /** - * Creates a symbol map from the specified resource bundle, - * - * @param rb - * the resource bundle. - */ - private SymbolMap(ResourceBundle rb) { - this(); - for (Enumeration i = rb.getKeys(); i.hasMoreElements();) { - String fqn = i.nextElement(); - String symbol = rb.getString(fqn); - boolean isAlias = false; - int lastDot = fqn.lastIndexOf('.'); - String className = fqn.substring(0, lastDot); - String fieldName = fqn.substring(lastDot + 1, fqn.length()); - if (Character.isDigit(fieldName.charAt(0))) { - isAlias = true; - fqn = className; - lastDot = fqn.lastIndexOf('.'); - className = fqn.substring(0, lastDot); - fieldName = fqn.substring(lastDot + 1, fqn.length()); - } - try { - Class c = Class.forName(className); - Field field = c.getField(fieldName); - Object value = field.get(null); - if (value instanceof Unit) { - if (isAlias) { - alias((Unit) value, symbol); - } else { - label((AbstractUnit) value, symbol); - } - } else if (value instanceof MetricPrefix) { - label((MetricPrefix) value, symbol); - } else { - throw new ClassCastException("unable to cast " + value + " to Unit or Prefix"); - } - } catch (Exception error) { - logger.log(Level.SEVERE, "Error", error); - } - } - } - - /** - * Creates a symbol map from the specified resource bundle, - * - * @param rb - * the resource bundle. - */ - public static SymbolMap of(ResourceBundle rb) { - return new SymbolMap(rb); - } - - /** - * Attaches a label to the specified unit. For example:
+/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +import tec.uom.se.AbstractConverter; +import tec.uom.se.AbstractUnit; +import tec.uom.se.unit.MetricPrefix; + +import javax.measure.Unit; +import javax.measure.UnitConverter; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.TreeMap; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + *

+ * This class provides a set of mappings between {@link AbstractUnit units} and symbols (both ways), between {@link MetricPrefix prefixes} and symbols + * (both ways), and from {@link AbstractConverter unit converters} to {@link MetricPrefix prefixes} (one way). No attempt is made to verify the + * uniqueness of the mappings. + *

+ * + *

+ * Mappings are read from a ResourceBundle, the keys of which should consist of a fully-qualified class name, followed by a dot ('.'), + * and then the name of a static field belonging to that class, followed optionally by another dot and a number. If the trailing dot and number are + * not present, the value associated with the key is treated as a {@link SymbolMap#label(AbstractUnit, String) label}, otherwise if the trailing dot + * and number are present, the value is treated as an {@link SymbolMap#alias(AbstractUnit,String) alias}. Aliases map from String to Unit only, + * whereas labels map in both directions. A given unit may have any number of aliases, but may have only one label. + *

+ * + * @author Eric Russell + * @author Werner Keil + * @version 1.7, February 25, 2017 + */ +@SuppressWarnings("rawtypes") +public final class SymbolMap { + private static final Logger logger = Logger.getLogger(SymbolMap.class.getName()); + + private final Map> symbolToUnit; + private final Map, String> unitToSymbol; + private final Map symbolToPrefix; + private final Map prefixToSymbol; + private final Map converterToPrefix; + + /** + * Creates an empty mapping. + */ + private SymbolMap() { + symbolToUnit = new TreeMap<>(); + unitToSymbol = new HashMap<>(); + symbolToPrefix = new TreeMap<>(); + prefixToSymbol = new HashMap<>(); + converterToPrefix = new HashMap<>(); + } + + /** + * Creates a symbol map from the specified resource bundle, + * + * @param rb + * the resource bundle. + */ + private SymbolMap(ResourceBundle rb) { + this(); + for (Enumeration i = rb.getKeys(); i.hasMoreElements();) { + String fqn = i.nextElement(); + String symbol = rb.getString(fqn); + boolean isAlias = false; + int lastDot = fqn.lastIndexOf('.'); + String className = fqn.substring(0, lastDot); + String fieldName = fqn.substring(lastDot + 1, fqn.length()); + if (Character.isDigit(fieldName.charAt(0))) { + isAlias = true; + fqn = className; + lastDot = fqn.lastIndexOf('.'); + className = fqn.substring(0, lastDot); + fieldName = fqn.substring(lastDot + 1, fqn.length()); + } + try { + Class c = Class.forName(className); + Field field = c.getField(fieldName); + Object value = field.get(null); + if (value instanceof Unit) { + if (isAlias) { + alias((Unit) value, symbol); + } else { + label((AbstractUnit) value, symbol); + } + } else if (value instanceof MetricPrefix) { + label((MetricPrefix) value, symbol); + } else { + throw new ClassCastException("unable to cast " + value + " to Unit or Prefix"); + } + } catch (Exception error) { + logger.log(Level.SEVERE, "Error", error); + } + } + } + + /** + * Creates a symbol map from the specified resource bundle, + * + * @param rb + * the resource bundle. + */ + public static SymbolMap of(ResourceBundle rb) { + return new SymbolMap(rb); + } + + /** + * Attaches a label to the specified unit. For example:
* symbolMap.label(DAY.multiply(365), "year"); symbolMap.label(US.FOOT, "ft"); - * - * - * @param unit - * the unit to label. - * @param symbol - * the new symbol for the unit. - */ - public void label(Unit unit, String symbol) { - symbolToUnit.put(symbol, unit); - unitToSymbol.put(unit, symbol); - } - - /** - * Attaches an alias to the specified unit. Multiple aliases may be attached to the same unit. Aliases are used during parsing to recognize + * + * + * @param unit + * the unit to label. + * @param symbol + * the new symbol for the unit. + */ + public void label(Unit unit, String symbol) { + symbolToUnit.put(symbol, unit); + unitToSymbol.put(unit, symbol); + } + + /** + * Attaches an alias to the specified unit. Multiple aliases may be attached to the same unit. Aliases are used during parsing to recognize * different variants of the same unit. symbolMap.alias(US.FOOT, "foot"); symbolMap.alias(US.FOOT, "feet"); - * symbolMap.alias(Units.METER, "meter"); symbolMap.alias(Units.METER, "metre"); - * - * @param unit - * the unit to label. - * @param symbol - * the new symbol for the unit. - */ - public void alias(Unit unit, String symbol) { - symbolToUnit.put(symbol, unit); - } - - /** - * Attaches a label to the specified prefix. For example:
+ * symbolMap.alias(Units.METER, "meter"); symbolMap.alias(Units.METER, "metre"); + * + * @param unit + * the unit to label. + * @param symbol + * the new symbol for the unit. + */ + public void alias(Unit unit, String symbol) { + symbolToUnit.put(symbol, unit); + } + + /** + * Attaches a label to the specified prefix. For example:
* symbolMap.label(MetricPrefix.GIGA, "G"); symbolMap.label(MetricPrefix.MICRO, "µ"); - * - */ - public void label(MetricPrefix prefix, String symbol) { - symbolToPrefix.put(symbol, prefix); - prefixToSymbol.put(prefix, symbol); - converterToPrefix.put(prefix.getConverter(), prefix); - } - - /** - * Returns the unit for the specified symbol. - * - * @param symbol - * the symbol. - * @return the corresponding unit or null if none. - */ - public Unit getUnit(String symbol) { - return symbolToUnit.get(symbol); - } - - /** - * Returns the symbol (label) for the specified unit. - * - * @param unit - * the corresponding symbol. - * @return the corresponding symbol or null if none. - */ - public String getSymbol(Unit unit) { - return unitToSymbol.get(unit); - } - - /** - * Returns the prefix (if any) for the specified symbol. - * - * @param symbol - * the unit symbol. - * @return the corresponding prefix or null if none. - */ + * + */ + public void label(MetricPrefix prefix, String symbol) { + symbolToPrefix.put(symbol, prefix); + prefixToSymbol.put(prefix, symbol); + converterToPrefix.put(prefix.getConverter(), prefix); + } + + /** + * Returns the unit for the specified symbol. + * + * @param symbol + * the symbol. + * @return the corresponding unit or null if none. + */ + public Unit getUnit(String symbol) { + return symbolToUnit.get(symbol); + } + + /** + * Returns the symbol (label) for the specified unit. + * + * @param unit + * the corresponding symbol. + * @return the corresponding symbol or null if none. + */ + public String getSymbol(Unit unit) { + return unitToSymbol.get(unit); + } + + /** + * Returns the prefix (if any) for the specified symbol. + * + * @param symbol + * the unit symbol. + * @return the corresponding prefix or null if none. + */ public MetricPrefix getPrefix(String symbol) { final List list = symbolToPrefix.keySet().stream().collect(Collectors.toList()); final Comparator comparator = Comparator.comparing(String::length); @@ -223,41 +223,41 @@ public MetricPrefix getPrefix(String symbol) { } return null; } - - /** - * Returns the prefix for the specified converter. - * - * @param converter - * the unit converter. - * @return the corresponding prefix or null if none. - */ - public MetricPrefix getPrefix(UnitConverter converter) { - return converterToPrefix.get(converter); - } - - /** - * Returns the symbol for the specified prefix. - * - * @param prefix - * the prefix. - * @return the corresponding symbol or null if none. - */ - public String getSymbol(MetricPrefix prefix) { - return prefixToSymbol.get(prefix); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("tec.uom.se.format.SymbolMap: ["); - sb.append("symbolToUnit: ").append(symbolToUnit).append(','); - sb.append("unitToSymbol: ").append(unitToSymbol).append(','); - sb.append("symbolToPrefix: ").append(symbolToPrefix).append(','); - sb.append("prefixToSymbol: ").append(prefixToSymbol).append(','); - sb.append("converterToPrefix: ").append(converterToPrefix).append(','); - sb.append("converterToPrefix: ").append(converterToPrefix); - sb.append(" ]"); - return sb.toString(); - } - -} + + /** + * Returns the prefix for the specified converter. + * + * @param converter + * the unit converter. + * @return the corresponding prefix or null if none. + */ + public MetricPrefix getPrefix(UnitConverter converter) { + return converterToPrefix.get(converter); + } + + /** + * Returns the symbol for the specified prefix. + * + * @param prefix + * the prefix. + * @return the corresponding symbol or null if none. + */ + public String getSymbol(MetricPrefix prefix) { + return prefixToSymbol.get(prefix); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("tec.uom.se.format.SymbolMap: ["); + sb.append("symbolToUnit: ").append(symbolToUnit).append(','); + sb.append("unitToSymbol: ").append(unitToSymbol).append(','); + sb.append("symbolToPrefix: ").append(symbolToPrefix).append(','); + sb.append("prefixToSymbol: ").append(prefixToSymbol).append(','); + sb.append("converterToPrefix: ").append(converterToPrefix).append(','); + sb.append("converterToPrefix: ").append(converterToPrefix); + sb.append(" ]"); + return sb.toString(); + } + +} diff --git a/src/main/java/tec/uom/se/format/UnitStyle.java b/src/main/java/tec/uom/se/format/UnitStyle.java index 5d6d1641..afb63091 100644 --- a/src/main/java/tec/uom/se/format/UnitStyle.java +++ b/src/main/java/tec/uom/se/format/UnitStyle.java @@ -1,69 +1,69 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.format; - -/** - * Defines the different variants of unit formatting. - * - * @author Werner Keil - * @version 1.0 - * @since 1.0.1 - */ -public enum UnitStyle { - - /** - * The unit will be rendered as its name. - * - * @see javax.measure.Unit#getName() - */ - NAME, - - /** - * The unit will be rendered as its symbol. - * - * @see javax.measure.Unit#getSymbol() - */ - SYMBOL, - - /** - * The unit will be rendered as its label. - * - * @see javax.measure.format.UnitFormat#label() - */ - LABEL, - - /** - * The unit will be rendered as its symbol and also labeled. - * - * @see javax.measure.Unit#getSymbol() - * @see javax.measure.format.UnitFormat#label() - */ - SYMBOL_AND_LABEL +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.format; + +/** + * Defines the different variants of unit formatting. + * + * @author Werner Keil + * @version 1.0 + * @since 1.0.1 + */ +public enum UnitStyle { + + /** + * The unit will be rendered as its name. + * + * @see javax.measure.Unit#getName() + */ + NAME, + + /** + * The unit will be rendered as its symbol. + * + * @see javax.measure.Unit#getSymbol() + */ + SYMBOL, + + /** + * The unit will be rendered as its label. + * + * @see javax.measure.format.UnitFormat#label() + */ + LABEL, + + /** + * The unit will be rendered as its symbol and also labeled. + * + * @see javax.measure.Unit#getSymbol() + * @see javax.measure.format.UnitFormat#label() + */ + SYMBOL_AND_LABEL } \ No newline at end of file diff --git a/src/main/java/tec/uom/se/function/AddConverter.java b/src/main/java/tec/uom/se/function/AddConverter.java index 0e9dc3ca..daf75394 100644 --- a/src/main/java/tec/uom/se/function/AddConverter.java +++ b/src/main/java/tec/uom/se/function/AddConverter.java @@ -1,140 +1,140 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Objects; - -import javax.measure.UnitConverter; - -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -/** - *

- * This class represents a converter adding a constant offset to numeric values (double based). - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, Oct 10, 2016 - */ -public final class AddConverter extends AbstractConverter implements ValueSupplier { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Objects; + +import javax.measure.UnitConverter; + +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +/** + *

+ * This class represents a converter adding a constant offset to numeric values (double based). + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, Oct 10, 2016 + */ +public final class AddConverter extends AbstractConverter implements ValueSupplier { + /** * - */ - private static final long serialVersionUID = -2981335308595652284L; - /** - * Holds the offset. - */ - private double offset; - - /** - * Creates an additive converter having the specified offset. - * - * @param offset - * the offset value. - * @throws IllegalArgumentException - * if offset is 0.0 (would result in identity converter). - */ - public AddConverter(double offset) { - if (offset == 0.0) - throw new IllegalArgumentException("Would result in identity converter"); - this.offset = offset; - } - - /** - * Returns the offset value for this add converter. - * - * @return the offset value. - */ - public double getOffset() { - return offset; - } - - @Override - public UnitConverter concatenate(UnitConverter converter) { - if (!(converter instanceof AddConverter)) - return super.concatenate(converter); - double newOffset = offset + ((AddConverter) converter).offset; - return newOffset == 0.0 ? IDENTITY : new AddConverter(newOffset); - } - - @Override - public AddConverter inverse() { - return new AddConverter(-offset); - } - - @Override - public double convert(double value) { - return value + offset; - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - return value.add(BigDecimal.valueOf(offset), ctx); - } - - @Override - public final String toString() { - return "AddConverter(" + offset + ")"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof AddConverter) { - AddConverter other = (AddConverter) obj; - return Objects.equals(offset, other.offset); - } - - return false; - } - - @Override - public int hashCode() { - return Objects.hashCode(offset); - } - - @Override - public boolean isLinear() { - return false; - } - - public Double getValue() { - return offset; - } - -} + */ + private static final long serialVersionUID = -2981335308595652284L; + /** + * Holds the offset. + */ + private double offset; + + /** + * Creates an additive converter having the specified offset. + * + * @param offset + * the offset value. + * @throws IllegalArgumentException + * if offset is 0.0 (would result in identity converter). + */ + public AddConverter(double offset) { + if (offset == 0.0) + throw new IllegalArgumentException("Would result in identity converter"); + this.offset = offset; + } + + /** + * Returns the offset value for this add converter. + * + * @return the offset value. + */ + public double getOffset() { + return offset; + } + + @Override + public UnitConverter concatenate(UnitConverter converter) { + if (!(converter instanceof AddConverter)) + return super.concatenate(converter); + double newOffset = offset + ((AddConverter) converter).offset; + return newOffset == 0.0 ? IDENTITY : new AddConverter(newOffset); + } + + @Override + public AddConverter inverse() { + return new AddConverter(-offset); + } + + @Override + public double convert(double value) { + return value + offset; + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + return value.add(BigDecimal.valueOf(offset), ctx); + } + + @Override + public final String toString() { + return "AddConverter(" + offset + ")"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof AddConverter) { + AddConverter other = (AddConverter) obj; + return Objects.equals(offset, other.offset); + } + + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(offset); + } + + @Override + public boolean isLinear() { + return false; + } + + public Double getValue() { + return offset; + } + +} diff --git a/src/main/java/tec/uom/se/function/Converter.java b/src/main/java/tec/uom/se/function/Converter.java index 7db754de..e7be67dd 100644 --- a/src/main/java/tec/uom/se/function/Converter.java +++ b/src/main/java/tec/uom/se/function/Converter.java @@ -1,55 +1,55 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -/** - * Represents an operation to convert values. - *

- * This is a functional interface - * whose functional method is {@link #convert()}. - * - * @author Werner Keil - * @version 1.0, 2016-10-11 - * @since 1.0 - * @param - * The type to convert to. - * @see Wikipedia: Data Conversion - */ -@FunctionalInterface -public interface Converter { - - /** - * Returns a F converted into a T. - * - * @param from - * @return the converted result. - */ - T convert(F from); -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +/** + * Represents an operation to convert values. + *

+ * This is a functional interface + * whose functional method is {@link #convert()}. + * + * @author Werner Keil + * @version 1.0, 2016-10-11 + * @since 1.0 + * @param + * The type to convert to. + * @see Wikipedia: Data Conversion + */ +@FunctionalInterface +public interface Converter { + + /** + * Returns a F converted into a T. + * + * @param from + * @return the converted result. + */ + T convert(F from); +} diff --git a/src/main/java/tec/uom/se/function/ExpConverter.java b/src/main/java/tec/uom/se/function/ExpConverter.java index 3f43bc93..863e51a1 100644 --- a/src/main/java/tec/uom/se/function/ExpConverter.java +++ b/src/main/java/tec/uom/se/function/ExpConverter.java @@ -1,141 +1,141 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Objects; - -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -/** - *

- * This class represents a exponential converter of limited precision. Such converter is used to create inverse of logarithmic unit. - * - *

- * This class is package private, instances are created using the {@link LogConverter#inverse()} method. - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, Oct 10, 2016 - * @since 1.0 - */ -public final class ExpConverter extends AbstractConverter implements ValueSupplier { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Objects; + +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +/** + *

+ * This class represents a exponential converter of limited precision. Such converter is used to create inverse of logarithmic unit. + * + *

+ * This class is package private, instances are created using the {@link LogConverter#inverse()} method. + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, Oct 10, 2016 + * @since 1.0 + */ +public final class ExpConverter extends AbstractConverter implements ValueSupplier { + /** * - */ - private static final long serialVersionUID = -8851436813812059827L; - - /** - * Holds the logarithmic base. - */ - private final double base; - - /** - * Holds the natural logarithm of the base. - */ - private final double logOfBase; - - /** - * Creates a logarithmic converter having the specified base. - * - * @param base - * the logarithmic base (e.g. Math.E for the Natural Logarithm). - */ - public ExpConverter(double base) { - this.base = base; - this.logOfBase = Math.log(base); - } - - /** - * Returns the exponential base of this converter. - * - * @return the exponential base (e.g. Math.E for the Natural Exponential). - */ - public double getBase() { - return base; - } - - @Override - public AbstractConverter inverse() { - return new LogConverter(base); - } - - @Override - public final String toString() { - if (base == Math.E) { - return "e"; - } else { - return "Exp(" + base + ")"; - } - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof ExpConverter) { - ExpConverter that = (ExpConverter) obj; - return Objects.equals(base, that.base); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(base); - } - - @Override - public double convert(double amount) { - return Math.exp(logOfBase * amount); - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to - // double - // conversion. - } - - @Override - public boolean isLinear() { - return false; - } - - @Override - public String getValue() { - return toString(); - } -} + */ + private static final long serialVersionUID = -8851436813812059827L; + + /** + * Holds the logarithmic base. + */ + private final double base; + + /** + * Holds the natural logarithm of the base. + */ + private final double logOfBase; + + /** + * Creates a logarithmic converter having the specified base. + * + * @param base + * the logarithmic base (e.g. Math.E for the Natural Logarithm). + */ + public ExpConverter(double base) { + this.base = base; + this.logOfBase = Math.log(base); + } + + /** + * Returns the exponential base of this converter. + * + * @return the exponential base (e.g. Math.E for the Natural Exponential). + */ + public double getBase() { + return base; + } + + @Override + public AbstractConverter inverse() { + return new LogConverter(base); + } + + @Override + public final String toString() { + if (base == Math.E) { + return "e"; + } else { + return "Exp(" + base + ")"; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExpConverter) { + ExpConverter that = (ExpConverter) obj; + return Objects.equals(base, that.base); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(base); + } + + @Override + public double convert(double amount) { + return Math.exp(logOfBase * amount); + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to + // double + // conversion. + } + + @Override + public boolean isLinear() { + return false; + } + + @Override + public String getValue() { + return toString(); + } +} diff --git a/src/main/java/tec/uom/se/function/LogConverter.java b/src/main/java/tec/uom/se/function/LogConverter.java index dab03c69..caef5052 100644 --- a/src/main/java/tec/uom/se/function/LogConverter.java +++ b/src/main/java/tec/uom/se/function/LogConverter.java @@ -1,138 +1,138 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Objects; - -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -/** - *

- * This class represents a logarithmic converter of limited precision. Such converter is typically used to create logarithmic unit. For example:[code] - * Unit BEL = Unit.ONE.transform(new LogConverter(10).inverse()); [/code] - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, October 10, 2016 - */ -public final class LogConverter extends AbstractConverter implements ValueSupplier { // implements Immutable { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Objects; + +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +/** + *

+ * This class represents a logarithmic converter of limited precision. Such converter is typically used to create logarithmic unit. For example:[code] + * Unit BEL = Unit.ONE.transform(new LogConverter(10).inverse()); [/code] + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, October 10, 2016 + */ +public final class LogConverter extends AbstractConverter implements ValueSupplier { // implements Immutable { + /** * - */ - private static final long serialVersionUID = -7584688290961460870L; - - /** - * Holds the logarithmic base. - */ - private final double base; - /** - * Holds the natural logarithm of the base. - */ - private final double logOfBase; - - /** - * Returns a logarithmic converter having the specified base. - * - * @param base - * the logarithmic base (e.g. Math.E for the Natural Logarithm). - */ - public LogConverter(double base) { - this.base = base; - this.logOfBase = Math.log(base); - } - - /** - * Returns the logarithmic base of this converter. - * - * @return the logarithmic base (e.g. Math.E for the Natural Logarithm). - */ - public double getBase() { - return base; - } - - @Override - public AbstractConverter inverse() { - return new ExpConverter(base); - } - - @Override - public final String toString() { - if (base == Math.E) { - return "ln"; - } else { - return "Log(" + base + ")"; - } - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof LogConverter) { - LogConverter that = (LogConverter) obj; - return Objects.equals(base, that.base); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(base); - } - - @Override - public double convert(double amount) { - return Math.log(amount) / logOfBase; - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to - // double - // conversion. - } - - @Override - public boolean isLinear() { - return false; - } - - @Override - public String getValue() { - return toString(); - } -} + */ + private static final long serialVersionUID = -7584688290961460870L; + + /** + * Holds the logarithmic base. + */ + private final double base; + /** + * Holds the natural logarithm of the base. + */ + private final double logOfBase; + + /** + * Returns a logarithmic converter having the specified base. + * + * @param base + * the logarithmic base (e.g. Math.E for the Natural Logarithm). + */ + public LogConverter(double base) { + this.base = base; + this.logOfBase = Math.log(base); + } + + /** + * Returns the logarithmic base of this converter. + * + * @return the logarithmic base (e.g. Math.E for the Natural Logarithm). + */ + public double getBase() { + return base; + } + + @Override + public AbstractConverter inverse() { + return new ExpConverter(base); + } + + @Override + public final String toString() { + if (base == Math.E) { + return "ln"; + } else { + return "Log(" + base + ")"; + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LogConverter) { + LogConverter that = (LogConverter) obj; + return Objects.equals(base, that.base); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(base); + } + + @Override + public double convert(double amount) { + return Math.log(amount) / logOfBase; + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + return BigDecimal.valueOf(convert(value.doubleValue())); // Reverts to + // double + // conversion. + } + + @Override + public boolean isLinear() { + return false; + } + + @Override + public String getValue() { + return toString(); + } +} diff --git a/src/main/java/tec/uom/se/function/MultiplyConverter.java b/src/main/java/tec/uom/se/function/MultiplyConverter.java index 85d8049a..1f3f919b 100644 --- a/src/main/java/tec/uom/se/function/MultiplyConverter.java +++ b/src/main/java/tec/uom/se/function/MultiplyConverter.java @@ -1,141 +1,141 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import javax.measure.UnitConverter; - -import tec.uom.lib.common.function.DoubleFactorSupplier; -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.Objects; - -/** - *

- * This class represents a converter multiplying numeric values by a constant scaling factor (double based). - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, Oct 11, 2016 - * @since 1.0 - */ -public final class MultiplyConverter extends AbstractConverter implements ValueSupplier, DoubleFactorSupplier { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import javax.measure.UnitConverter; + +import tec.uom.lib.common.function.DoubleFactorSupplier; +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.Objects; + +/** + *

+ * This class represents a converter multiplying numeric values by a constant scaling factor (double based). + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, Oct 11, 2016 + * @since 1.0 + */ +public final class MultiplyConverter extends AbstractConverter implements ValueSupplier, DoubleFactorSupplier { + /** * - */ - private static final long serialVersionUID = 6588759878444545649L; - - /** - * Holds the scale factor. - */ - private double factor; - - /** - * Creates a multiply converter with the specified scale factor. - * - * @param factor - * the scaling factor. - * @throws IllegalArgumentException - * if coefficient is 1.0 (would result in identity converter) - */ - public MultiplyConverter(double factor) { - if (factor == 1.0) - throw new IllegalArgumentException("Would result in identity converter"); - this.factor = factor; - } - - /** - * Returns the scale factor of this converter. - * - * @return the scale factor. - */ - public double getFactor() { - return factor; - } - - @Override - public UnitConverter concatenate(UnitConverter converter) { - if (!(converter instanceof MultiplyConverter)) - return super.concatenate(converter); - double newfactor = factor * ((MultiplyConverter) converter).factor; - return newfactor == 1.0 ? IDENTITY : new MultiplyConverter(newfactor); - } - - @Override - public MultiplyConverter inverse() { - return new MultiplyConverter(1.0 / factor); - } - - @Override - public double convert(double value) { - return value * factor; - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - return value.multiply(BigDecimal.valueOf(factor), ctx); - } - - @Override - public final String toString() { - return MultiplyConverter.class.getSimpleName() + "(" + factor + ")"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof MultiplyConverter) { - MultiplyConverter that = (MultiplyConverter) obj; - return Objects.equals(factor, that.factor); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hashCode(factor); - } - - @Override - public boolean isLinear() { - return true; - } - - @Override - public Double getValue() { - return factor; - } -} + */ + private static final long serialVersionUID = 6588759878444545649L; + + /** + * Holds the scale factor. + */ + private double factor; + + /** + * Creates a multiply converter with the specified scale factor. + * + * @param factor + * the scaling factor. + * @throws IllegalArgumentException + * if coefficient is 1.0 (would result in identity converter) + */ + public MultiplyConverter(double factor) { + if (factor == 1.0) + throw new IllegalArgumentException("Would result in identity converter"); + this.factor = factor; + } + + /** + * Returns the scale factor of this converter. + * + * @return the scale factor. + */ + public double getFactor() { + return factor; + } + + @Override + public UnitConverter concatenate(UnitConverter converter) { + if (!(converter instanceof MultiplyConverter)) + return super.concatenate(converter); + double newfactor = factor * ((MultiplyConverter) converter).factor; + return newfactor == 1.0 ? IDENTITY : new MultiplyConverter(newfactor); + } + + @Override + public MultiplyConverter inverse() { + return new MultiplyConverter(1.0 / factor); + } + + @Override + public double convert(double value) { + return value * factor; + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + return value.multiply(BigDecimal.valueOf(factor), ctx); + } + + @Override + public final String toString() { + return MultiplyConverter.class.getSimpleName() + "(" + factor + ")"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MultiplyConverter) { + MultiplyConverter that = (MultiplyConverter) obj; + return Objects.equals(factor, that.factor); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(factor); + } + + @Override + public boolean isLinear() { + return true; + } + + @Override + public Double getValue() { + return factor; + } +} diff --git a/src/main/java/tec/uom/se/function/NaturalOrder.java b/src/main/java/tec/uom/se/function/NaturalOrder.java index 4ce56b31..620f5eef 100644 --- a/src/main/java/tec/uom/se/function/NaturalOrder.java +++ b/src/main/java/tec/uom/se/function/NaturalOrder.java @@ -1,67 +1,67 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.util.Comparator; - -import javax.measure.Quantity; - -/** - * Comparator to sort by natural order, looking both the unit and the value. - * - * @author Werner Keil - * @author Otavio Santana - * @version 1.0 - * @return Given: - *

- * Quantity

- *

- * Quantity

- *

- * Quantity

- *

- * Quantity

- * will return: seconds, minutes, hours, day - * @since 1.0 - */ -public class NaturalOrder> implements Comparator> { - - @Override - public int compare(Quantity q1, Quantity q2) { - if (q1.getUnit().equals(q2.getUnit())) { - return Double.compare(q1.getValue().doubleValue(), q2.getValue().doubleValue()); - } - return Double.compare(q1.getValue().doubleValue(), q2.to(q1.getUnit()).getValue().doubleValue()); - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.util.Comparator; + +import javax.measure.Quantity; + +/** + * Comparator to sort by natural order, looking both the unit and the value. + * + * @author Werner Keil + * @author Otavio Santana + * @version 1.0 + * @return Given: + *

+ * Quantity

+ *

+ * Quantity

+ *

+ * Quantity

+ *

+ * Quantity

+ * will return: seconds, minutes, hours, day + * @since 1.0 + */ +public class NaturalOrder> implements Comparator> { + + @Override + public int compare(Quantity q1, Quantity q2) { + if (q1.getUnit().equals(q2.getUnit())) { + return Double.compare(q1.getValue().doubleValue(), q2.getValue().doubleValue()); + } + return Double.compare(q1.getValue().doubleValue(), q2.to(q1.getUnit()).getValue().doubleValue()); + } +} diff --git a/src/main/java/tec/uom/se/function/PiDivisorConverter.java b/src/main/java/tec/uom/se/function/PiDivisorConverter.java index acdd01fd..f96968c3 100644 --- a/src/main/java/tec/uom/se/function/PiDivisorConverter.java +++ b/src/main/java/tec/uom/se/function/PiDivisorConverter.java @@ -1,108 +1,108 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.math.BigDecimal; -import java.math.MathContext; - -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -/** - *

- * This class represents a converter dividing numeric values by π (Pi). - *

- * - *

- * This class is package private, instances are created using the {@link PiMultiplierConverter#inverse()} method. - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, October 11, 2016 - * @since 1.0 - */ -final class PiDivisorConverter extends AbstractConverter implements ValueSupplier { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.math.BigDecimal; +import java.math.MathContext; + +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +/** + *

+ * This class represents a converter dividing numeric values by π (Pi). + *

+ * + *

+ * This class is package private, instances are created using the {@link PiMultiplierConverter#inverse()} method. + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, October 11, 2016 + * @since 1.0 + */ +final class PiDivisorConverter extends AbstractConverter implements ValueSupplier { + /** * - */ - private static final long serialVersionUID = 5052794216568914141L; - - /** - * Creates a Pi multiplier converter. - */ - public PiDivisorConverter() { - } - - @Override - public double convert(double value) { - return value / PI; - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - int nbrDigits = ctx.getPrecision(); - if (nbrDigits == 0) - throw new ArithmeticException("Pi multiplication with unlimited precision"); - BigDecimal pi = PiMultiplierConverter.Pi.pi(nbrDigits); - return value.divide(pi, ctx); - } - - @Override - public AbstractConverter inverse() { - return new PiMultiplierConverter(); - } - - @Override - public final String toString() { - return "(1/π)"; - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof PiDivisorConverter); - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public boolean isLinear() { - return true; - } - - @Override - public String getValue() { - return toString(); - } -} + */ + private static final long serialVersionUID = 5052794216568914141L; + + /** + * Creates a Pi multiplier converter. + */ + public PiDivisorConverter() { + } + + @Override + public double convert(double value) { + return value / PI; + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + int nbrDigits = ctx.getPrecision(); + if (nbrDigits == 0) + throw new ArithmeticException("Pi multiplication with unlimited precision"); + BigDecimal pi = PiMultiplierConverter.Pi.pi(nbrDigits); + return value.divide(pi, ctx); + } + + @Override + public AbstractConverter inverse() { + return new PiMultiplierConverter(); + } + + @Override + public final String toString() { + return "(1/π)"; + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof PiDivisorConverter); + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean isLinear() { + return true; + } + + @Override + public String getValue() { + return toString(); + } +} diff --git a/src/main/java/tec/uom/se/function/PiMultiplierConverter.java b/src/main/java/tec/uom/se/function/PiMultiplierConverter.java index 68412dfd..dee7c643 100644 --- a/src/main/java/tec/uom/se/function/PiMultiplierConverter.java +++ b/src/main/java/tec/uom/se/function/PiMultiplierConverter.java @@ -1,176 +1,176 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.math.RoundingMode; -import java.util.logging.Level; -import java.util.logging.Logger; - -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -/** - *

- * This class represents a converter multiplying numeric values by π (Pi). - *

- * - * @see Wikipedia: Pi - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0.1, November 3, 2016 - * @since 1.0 - */ -public final class PiMultiplierConverter extends AbstractConverter implements ValueSupplier { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.logging.Level; +import java.util.logging.Logger; + +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +/** + *

+ * This class represents a converter multiplying numeric values by π (Pi). + *

+ * + * @see Wikipedia: Pi + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0.1, November 3, 2016 + * @since 1.0 + */ +public final class PiMultiplierConverter extends AbstractConverter implements ValueSupplier { + /** * - */ - private static final long serialVersionUID = -5763262154104962367L; - - private static final Logger logger = Logger.getLogger(PiMultiplierConverter.class.getName()); - - /** - * Creates a Pi multiplier converter. - */ - public PiMultiplierConverter() { - } - - @Override - public double convert(double value) { - return value * PI; - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - int nbrDigits = ctx.getPrecision(); - if (nbrDigits == 0) - throw new ArithmeticException("Pi multiplication with unlimited precision"); - BigDecimal pi = Pi.pi(nbrDigits); - return value.multiply(pi, ctx); - } - - @Override - public AbstractConverter inverse() { - return new PiDivisorConverter(); - } - - @Override - public final String toString() { - return "(π)"; - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof PiMultiplierConverter); - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public boolean isLinear() { - return true; - } - - /** - * Pi calculation with Machin's formula. - * - * @see Pi with Machin's formula - * - */ - static final class Pi { - - private Pi() { - } - - public static BigDecimal pi(int numDigits) { - int calcDigits = numDigits + 10; - return FOUR.multiply((FOUR.multiply(arccot(FIVE, calcDigits))).subtract(arccot(TWO_THIRTY_NINE, calcDigits))).setScale(numDigits, - RoundingMode.DOWN); - } - - /* - * private static BigDecimal compute(int numDigits, boolean verbose) { - * int calcDigits = numDigits + 10; - * - * return FOUR .multiply((FOUR.multiply(arccot(FIVE, - * calcDigits))).subtract(arccot(TWO_THIRTY_NINE, calcDigits))) - * .setScale(numDigits, RoundingMode.DOWN); } - */ - /** Compute arccot via the Taylor series expansion. */ - private static BigDecimal arccot(BigDecimal x, int numDigits) { - BigDecimal unity = BigDecimal.ONE.setScale(numDigits, RoundingMode.DOWN); - BigDecimal sum = unity.divide(x, RoundingMode.DOWN); - BigDecimal xpower = new BigDecimal(sum.toString()); - BigDecimal term = null; - int nTerms = 0; - - BigDecimal nearZero = BigDecimal.ONE.scaleByPowerOfTen(-numDigits); - logger.log(Level.FINER, "arccot: ARGUMENT=" + x + " (nearZero=" + nearZero + ")"); - boolean add = false; - // Add one term of Taylor series each time thru loop. Stop looping - // when _term_ - // gets very close to zero. - for (BigDecimal n = THREE; term == null || !term.equals(BigDecimal.ZERO); n = n.add(TWO)) { - if (term != null && term.compareTo(nearZero) < 0) - break; - xpower = xpower.divide(x.pow(2), RoundingMode.DOWN); - term = xpower.divide(n, RoundingMode.DOWN); - sum = add ? sum.add(term) : sum.subtract(term); - add = !add; - // System.out.println("arccot: xpower=" + xpower + ", term=" + - // term); - logger.log(Level.FINEST, "arccot: term=" + term); - nTerms++; - } - logger.log(Level.FINER, "arccot: done. nTerms=" + nTerms); - return sum; - } - } - - private static final BigDecimal TWO = new BigDecimal("2"); - - private static final BigDecimal THREE = new BigDecimal("3"); - - private static final BigDecimal FOUR = new BigDecimal("4"); - - private static final BigDecimal FIVE = new BigDecimal("5"); - - private static final BigDecimal TWO_THIRTY_NINE = new BigDecimal("239"); - - @Override - public String getValue() { - return toString(); - } -} + */ + private static final long serialVersionUID = -5763262154104962367L; + + private static final Logger logger = Logger.getLogger(PiMultiplierConverter.class.getName()); + + /** + * Creates a Pi multiplier converter. + */ + public PiMultiplierConverter() { + } + + @Override + public double convert(double value) { + return value * PI; + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + int nbrDigits = ctx.getPrecision(); + if (nbrDigits == 0) + throw new ArithmeticException("Pi multiplication with unlimited precision"); + BigDecimal pi = Pi.pi(nbrDigits); + return value.multiply(pi, ctx); + } + + @Override + public AbstractConverter inverse() { + return new PiDivisorConverter(); + } + + @Override + public final String toString() { + return "(π)"; + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof PiMultiplierConverter); + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean isLinear() { + return true; + } + + /** + * Pi calculation with Machin's formula. + * + * @see Pi with Machin's formula + * + */ + static final class Pi { + + private Pi() { + } + + public static BigDecimal pi(int numDigits) { + int calcDigits = numDigits + 10; + return FOUR.multiply((FOUR.multiply(arccot(FIVE, calcDigits))).subtract(arccot(TWO_THIRTY_NINE, calcDigits))).setScale(numDigits, + RoundingMode.DOWN); + } + + /* + * private static BigDecimal compute(int numDigits, boolean verbose) { + * int calcDigits = numDigits + 10; + * + * return FOUR .multiply((FOUR.multiply(arccot(FIVE, + * calcDigits))).subtract(arccot(TWO_THIRTY_NINE, calcDigits))) + * .setScale(numDigits, RoundingMode.DOWN); } + */ + /** Compute arccot via the Taylor series expansion. */ + private static BigDecimal arccot(BigDecimal x, int numDigits) { + BigDecimal unity = BigDecimal.ONE.setScale(numDigits, RoundingMode.DOWN); + BigDecimal sum = unity.divide(x, RoundingMode.DOWN); + BigDecimal xpower = new BigDecimal(sum.toString()); + BigDecimal term = null; + int nTerms = 0; + + BigDecimal nearZero = BigDecimal.ONE.scaleByPowerOfTen(-numDigits); + logger.log(Level.FINER, "arccot: ARGUMENT=" + x + " (nearZero=" + nearZero + ")"); + boolean add = false; + // Add one term of Taylor series each time thru loop. Stop looping + // when _term_ + // gets very close to zero. + for (BigDecimal n = THREE; term == null || !term.equals(BigDecimal.ZERO); n = n.add(TWO)) { + if (term != null && term.compareTo(nearZero) < 0) + break; + xpower = xpower.divide(x.pow(2), RoundingMode.DOWN); + term = xpower.divide(n, RoundingMode.DOWN); + sum = add ? sum.add(term) : sum.subtract(term); + add = !add; + // System.out.println("arccot: xpower=" + xpower + ", term=" + + // term); + logger.log(Level.FINEST, "arccot: term=" + term); + nTerms++; + } + logger.log(Level.FINER, "arccot: done. nTerms=" + nTerms); + return sum; + } + } + + private static final BigDecimal TWO = new BigDecimal("2"); + + private static final BigDecimal THREE = new BigDecimal("3"); + + private static final BigDecimal FOUR = new BigDecimal("4"); + + private static final BigDecimal FIVE = new BigDecimal("5"); + + private static final BigDecimal TWO_THIRTY_NINE = new BigDecimal("239"); + + @Override + public String getValue() { + return toString(); + } +} diff --git a/src/main/java/tec/uom/se/function/QuantityConverter.java b/src/main/java/tec/uom/se/function/QuantityConverter.java index 79563272..2410ffaa 100644 --- a/src/main/java/tec/uom/se/function/QuantityConverter.java +++ b/src/main/java/tec/uom/se/function/QuantityConverter.java @@ -1,58 +1,58 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import javax.measure.Quantity; -import javax.measure.Unit; - -/** - * Represents an operation to convert values. - *

- * This is a functional interface - * whose functional method is {@link #to()}. - * - * @author Werner Keil - * @version 1.0, 2016-10-11 - * @param - * The type to convert to. - * @see Wikipedia: Data Conversion - * @since 1.0 - */ -@FunctionalInterface -public interface QuantityConverter> { - - /** - * Returns a quantity converted into another unit. - * - * @param type - * @return the converted result. - */ - Quantity to(Unit type); -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import javax.measure.Quantity; +import javax.measure.Unit; + +/** + * Represents an operation to convert values. + *

+ * This is a functional interface + * whose functional method is {@link #to()}. + * + * @author Werner Keil + * @version 1.0, 2016-10-11 + * @param + * The type to convert to. + * @see Wikipedia: Data Conversion + * @since 1.0 + */ +@FunctionalInterface +public interface QuantityConverter> { + + /** + * Returns a quantity converted into another unit. + * + * @param type + * @return the converted result. + */ + Quantity to(Unit type); +} diff --git a/src/main/java/tec/uom/se/function/QuantityFunctions.java b/src/main/java/tec/uom/se/function/QuantityFunctions.java index 1ee81d26..9cf32ddc 100644 --- a/src/main/java/tec/uom/se/function/QuantityFunctions.java +++ b/src/main/java/tec/uom/se/function/QuantityFunctions.java @@ -1,193 +1,193 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.util.Comparator; -import java.util.Objects; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collector; - -import javax.measure.Quantity; -import javax.measure.Unit; - -/** - * @author Otavio - * @author Werner - * @version 1.0 - * @since 1.0 - * - */ -@SuppressWarnings("rawtypes") -public final class QuantityFunctions { - - private QuantityFunctions() { - } - - /** - * Creates a comparator to sort by number, ignoring the unit. - * - * @return

- * Given: - *

+/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.util.Comparator; +import java.util.Objects; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collector; + +import javax.measure.Quantity; +import javax.measure.Unit; + +/** + * @author Otavio + * @author Werner + * @version 1.0 + * @since 1.0 + * + */ +@SuppressWarnings("rawtypes") +public final class QuantityFunctions { + + private QuantityFunctions() { + } + + /** + * Creates a comparator to sort by number, ignoring the unit. + * + * @return

+ * Given: + *

* * Quantity - *

- * will return: day, hours, minutes, seconds - *

- * @throws NullPointerException - */ + * + *

+ * will return: day, hours, minutes, seconds + *

+ * @throws NullPointerException + */ public static > Comparator> sortNumber() { return (q1, q2) -> Double.compare(q1.getValue().doubleValue(), q2.getValue().doubleValue()); } - - /** - * Creates a comparator to sort by number descending, ignoring the unit. - * - * @return

- * Given: - *

+ + /** + * Creates a comparator to sort by number descending, ignoring the unit. + * + * @return

+ * Given: + *

* * Quantity - *

- * will return: seconds, hours, minutes, day - *

- * @throws NullPointerException - */ - public static > Comparator> sortNumberDesc() { - Comparator> sortNumber = sortNumber(); - return sortNumber.reversed(); - } - - /** - * Creates a comparator to sort by name, ignoring the value. - * - * @return

- * Given: - *

+ * + *

+ * will return: seconds, hours, minutes, day + *

+ * @throws NullPointerException + */ + public static > Comparator> sortNumberDesc() { + Comparator> sortNumber = sortNumber(); + return sortNumber.reversed(); + } + + /** + * Creates a comparator to sort by name, ignoring the value. + * + * @return

+ * Given: + *

* * Quantity - *

- * will return: day, hours, minutes, seconds - *

- * @throws NullPointerException - */ + * + *

+ * will return: day, hours, minutes, seconds + *

+ * @throws NullPointerException + */ public static > Comparator> sortSymbol() { return (q1, q2) -> q1.getUnit().getSymbol().compareTo(q2.getUnit().getSymbol()); } - - /** - * Creates a comparator to sort by name descending, ignoring the value. - * - * @return

- * Given: - *

+ + /** + * Creates a comparator to sort by name descending, ignoring the value. + * + * @return

+ * Given: + *

* * Quantity - *

- * will return: seconds, minutes, hour, day - *

- * @throws NullPointerException - */ - public static > Comparator> sortSymbolDesc() { - Comparator> sortSymbol = sortSymbol(); - return sortSymbol.reversed(); - } - - /** - * Creates a comparator to sort by natural order, looking to both the unit and the value. - * - * @return

- * Given: - *

+ * + *

+ * will return: seconds, minutes, hour, day + *

+ * @throws NullPointerException + */ + public static > Comparator> sortSymbolDesc() { + Comparator> sortSymbol = sortSymbol(); + return sortSymbol.reversed(); + } + + /** + * Creates a comparator to sort by natural order, looking to both the unit and the value. + * + * @return

+ * Given: + *

* * Quantity - *

- * will return: seconds, minutes, hours, day - *

- * @throws NullPointerException - */ - @SuppressWarnings("unchecked") - public static > Comparator> sortNatural() { - return new NaturalOrder(); - } - - /** - * Creates a comparator to sort by natural order descending, looking to both the unit and the value. - * - * @return

- * Given: - *

+ * + *

+ * will return: seconds, minutes, hours, day + *

+ * @throws NullPointerException + */ + @SuppressWarnings("unchecked") + public static > Comparator> sortNatural() { + return new NaturalOrder(); + } + + /** + * Creates a comparator to sort by natural order descending, looking to both the unit and the value. + * + * @return

+ * Given: + *

* * Quantity - *

- * will return: day, hour, minute, second - *

- * @throws NullPointerException - */ - public static > Comparator> sortNaturalDesc() { - Comparator> sortNatural = sortNatural(); - return sortNatural.reversed(); - } - - /** - * Creates a BinaryOperator to calculate the minimum Quantity - * - * @return the min BinaryOperator, not null. - */ + * + *

+ * will return: day, hour, minute, second + *

+ * @throws NullPointerException + */ + public static > Comparator> sortNaturalDesc() { + Comparator> sortNatural = sortNatural(); + return sortNatural.reversed(); + } + + /** + * Creates a BinaryOperator to calculate the minimum Quantity + * + * @return the min BinaryOperator, not null. + */ public static > BinaryOperator> min() { return (q1, q2) -> { @@ -200,12 +200,12 @@ public static > BinaryOperator> min() { return q2; }; } - - /** - * Creates a BinaryOperator to calculate the maximum Quantity - * - * @return the max BinaryOperator, not null. - */ + + /** + * Creates a BinaryOperator to calculate the maximum Quantity + * + * @return the max BinaryOperator, not null. + */ public static > BinaryOperator> max() { return (q1, q2) -> { @@ -218,34 +218,34 @@ public static > BinaryOperator> max() { return q2; }; } - - /** - * Creates a BinaryOperator to sum. - * - * @return the sum BinaryOperator - */ + + /** + * Creates a BinaryOperator to sum. + * + * @return the sum BinaryOperator + */ public static > BinaryOperator> sum() { return Quantity::add; } - - /** - * Creates a BinaryOperator to sum converting to unit - * - * @param unit - * unit to be converting - * @return the sum BinaryOperator converting to unit - */ + + /** + * Creates a BinaryOperator to sum converting to unit + * + * @param unit + * unit to be converting + * @return the sum BinaryOperator converting to unit + */ public static > BinaryOperator> sum(Unit unit) { return (q1, q2) -> q1.to(unit).add(q2.to(unit)); } - - /** - * Predicate to filter to one or more units - * - * @param units - * - units to be filtered (optional) - * @return A predicate to filter one or more units - */ + + /** + * Predicate to filter to one or more units + * + * @param units + * - units to be filtered (optional) + * @return A predicate to filter one or more units + */ @SafeVarargs public static > Predicate> fiterByUnit(Unit... units) { @@ -262,14 +262,14 @@ public static > Predicate> fiterByUnit(Unit } return predicate; } - - /** - * Predicate to filter excluding these units - * - * @param units - * - units to be filtered (optional) - * @return A predicate to filter to not be these units - */ + + /** + * Predicate to filter excluding these units + * + * @param units + * - units to be filtered (optional) + * @return A predicate to filter to not be these units + */ @SafeVarargs public static > Predicate> fiterByExcludingUnit(Unit... units) { if (Objects.isNull(units) || units.length == 0) { @@ -277,135 +277,135 @@ public static > Predicate> fiterByExcludingUni } return fiterByUnit(units).negate(); } - - /** - * creates a Filter to greater than number, ignoring units - * - * @param value - * - the value to be used in Predicate - * @return the Predicate greater than this number, ignoring units - */ + + /** + * creates a Filter to greater than number, ignoring units + * + * @param value + * - the value to be used in Predicate + * @return the Predicate greater than this number, ignoring units + */ public static > Predicate> isGreaterThan(Number value) { return q -> q.getValue().doubleValue() > value.doubleValue(); } - - /** - * creates a filter to greater than the quantity measure - * - * @param quantity - * - the measure to be used in filter - * @return the Predicate greater than this measure - */ + + /** + * creates a filter to greater than the quantity measure + * + * @param quantity + * - the measure to be used in filter + * @return the Predicate greater than this measure + */ public static > Predicate> isGreaterThan(Quantity quantity) { return q -> q.to(quantity.getUnit()).getValue().doubleValue() > quantity.getValue().doubleValue(); } - - /** - * creates a Filter to greater or equals than number, ignoring units - * - * @param value - * - the value to be used in Predicate - * @return the Predicate greater or equals than this number, ignoring units - */ + + /** + * creates a Filter to greater or equals than number, ignoring units + * + * @param value + * - the value to be used in Predicate + * @return the Predicate greater or equals than this number, ignoring units + */ public static > Predicate> isGreaterThanOrEqualTo(Number value) { return q -> q.getValue().doubleValue() >= value.doubleValue(); } - - /** - * creates a filter to greater or equals than the quantity measure - * - * @param quantity - * - the measure to be used in filter - * @return the Predicate greater or equals than this measure - */ + + /** + * creates a filter to greater or equals than the quantity measure + * + * @param quantity + * - the measure to be used in filter + * @return the Predicate greater or equals than this measure + */ public static > Predicate> isGreaterThanOrEqualTo(Quantity quantity) { return q -> q.to(quantity.getUnit()).getValue().doubleValue() >= quantity.getValue().doubleValue(); } - - /** - * creates a Filter to lesser than number, ignoring units - * - * @param value - * - the value to be used in Predicate - * @return the Predicate greater than this number, ignoring units - */ + + /** + * creates a Filter to lesser than number, ignoring units + * + * @param value + * - the value to be used in Predicate + * @return the Predicate greater than this number, ignoring units + */ public static > Predicate> isLesserThan(Number value) { return q -> q.getValue().doubleValue() < value.doubleValue(); } - - /** - * creates a filter to lesser than the quantity measure - * - * @param quantity - * - the measure to be used in filter - * @return the Predicate lesser than this measure - */ + + /** + * creates a filter to lesser than the quantity measure + * + * @param quantity + * - the measure to be used in filter + * @return the Predicate lesser than this measure + */ public static > Predicate> isLesserThan(Quantity quantity) { return q -> q.to(quantity.getUnit()).getValue().doubleValue() < quantity.getValue().doubleValue(); } - - /** - * creates a Filter to lesser or equals than number, ignoring units - * - * @param value - * - the value to be used in Predicate - * @return the Predicate lesser or equals than this number, ignoring units - */ + + /** + * creates a Filter to lesser or equals than number, ignoring units + * + * @param value + * - the value to be used in Predicate + * @return the Predicate lesser or equals than this number, ignoring units + */ public static > Predicate> isLesserThanOrEqualTo(Number value) { return q -> q.getValue().doubleValue() <= value.doubleValue(); } - - /** - * creates a filter to lesser or equals than the quantity measure - * - * @param quantity - * - the measure to be used in filter - * @return the Predicate lesser or equals than this measure - */ + + /** + * creates a filter to lesser or equals than the quantity measure + * + * @param quantity + * - the measure to be used in filter + * @return the Predicate lesser or equals than this measure + */ public static > Predicate> isLesserThanOrEqualTo(Quantity quantity) { return q -> q.to(quantity.getUnit()).getValue().doubleValue() <= quantity.getValue().doubleValue(); } - - /** - * creates a Filter to between, lesser or equals and greater or equals, than number, ignoring units - * - * @param min - * - the min value to be used in Predicate - * @param max - * - the max value to be used in Predicate - * @return the Predicate lesser or equals than this number, ignoring units - */ - public static > Predicate> isBetween(Number min, Number max) { - Predicate> minFilter = isGreaterThanOrEqualTo(min); - Predicate> maxFilter = isLesserThanOrEqualTo(max); - return minFilter.and(maxFilter); - } - - /** - * creates a filter to between, lesser or equals and greater or equals, than the quantity measure - * - * @param min - * - the min value to be used in Predicate - * @param max - * - the max value to be used in Predicate - * @return the Predicate lesser or equals than this measure - */ - public static > Predicate> isBetween(Quantity min, Quantity max) { - return isGreaterThanOrEqualTo(min).and(isLesserThanOrEqualTo(max)); - } - - /** - * Summary of Quantity - * - * @return the QuantitySummaryStatistics - */ + + /** + * creates a Filter to between, lesser or equals and greater or equals, than number, ignoring units + * + * @param min + * - the min value to be used in Predicate + * @param max + * - the max value to be used in Predicate + * @return the Predicate lesser or equals than this number, ignoring units + */ + public static > Predicate> isBetween(Number min, Number max) { + Predicate> minFilter = isGreaterThanOrEqualTo(min); + Predicate> maxFilter = isLesserThanOrEqualTo(max); + return minFilter.and(maxFilter); + } + + /** + * creates a filter to between, lesser or equals and greater or equals, than the quantity measure + * + * @param min + * - the min value to be used in Predicate + * @param max + * - the max value to be used in Predicate + * @return the Predicate lesser or equals than this measure + */ + public static > Predicate> isBetween(Quantity min, Quantity max) { + return isGreaterThanOrEqualTo(min).and(isLesserThanOrEqualTo(max)); + } + + /** + * Summary of Quantity + * + * @return the QuantitySummaryStatistics + */ public static > Collector, QuantitySummaryStatistics, QuantitySummaryStatistics> summarizeQuantity( Unit unit) { Supplier> supplier = () -> new QuantitySummaryStatistics<>(unit); return Collector.of(supplier, QuantitySummaryStatistics::accept, QuantitySummaryStatistics::combine); } - + public static > Function, Unit> groupByUnit() { return Quantity::getUnit; } -} +} diff --git a/src/main/java/tec/uom/se/function/QuantitySummaryStatistics.java b/src/main/java/tec/uom/se/function/QuantitySummaryStatistics.java index 65096f39..645a427f 100644 --- a/src/main/java/tec/uom/se/function/QuantitySummaryStatistics.java +++ b/src/main/java/tec/uom/se/function/QuantitySummaryStatistics.java @@ -1,268 +1,268 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import java.util.Objects; -import java.util.function.BinaryOperator; - -import javax.measure.Quantity; -import javax.measure.Unit; - -import tec.uom.se.quantity.Quantities; - -/** - * @author Otavio - * @author Werner - * @version 1.0 - * @since 1.0 - * @param - */ -public class QuantitySummaryStatistics> { - - private final Quantity empty; - - private long count; - - private Quantity min; - - private Quantity max; - - private Quantity sum; - - private Quantity average; - - private final BinaryOperator> minFunctions = QuantityFunctions.min(); - - private final BinaryOperator> maxFunctions = QuantityFunctions.max(); - - /** - * Creates a new instance, targeting the given {@link javax.measure.Unit}. - * - * @param unit - * the target unit, not null. - */ - QuantitySummaryStatistics(Unit unit) { - empty = Quantities.getQuantity(0, unit); - setQuantity(empty); - } - - /** - * Records another value into the summary information. - * - * @param quantity - * the input quantity value to be added, not null. - */ - public void accept(Quantity quantity) { - - Objects.requireNonNull(quantity); - - if (isEmpty()) { - setQuantity(quantity.to(empty.getUnit())); - count++; - } else { - doSummary(quantity.to(empty.getUnit())); - } - } - - /** - * Combines the state of another {@code QuantitySummaryStatistics} into this one. - * - * @param quantitySummary - * another {@code QuantitySummaryStatistics}, not null. - */ - public QuantitySummaryStatistics combine(QuantitySummaryStatistics quantitySummary) { - Objects.requireNonNull(quantitySummary); - - if (!equals(quantitySummary)) { - return this; - } - - min = minFunctions.apply(min, quantitySummary.min.to(empty.getUnit())); - max = maxFunctions.apply(max, quantitySummary.max.to(empty.getUnit())); - sum = sum.add(quantitySummary.sum); - count += quantitySummary.count; - average = sum.divide(count); - return this; - } - - private void doSummary(Quantity moneraty) { - min = minFunctions.apply(min, moneraty); - max = maxFunctions.apply(max, moneraty); - sum = sum.add(moneraty); - average = sum.divide(++count); - } - - private boolean isEmpty() { - return count == 0; - } - - private void setQuantity(Quantity quantity) { - min = quantity; - max = quantity; - sum = quantity; - average = quantity; - } - - /** - * Get the number of items added to this summary instance. - * - * @return the number of summarized items, >= 0. - */ - public long getCount() { - return count; - } - - /** - * Get the minimal quantity found within this summary. - * - * @return the minimal quantity - */ - public Quantity getMin() { - return min; - } - - /** - * Get the minimal quantity found within this summary converted to unit - * - * @param unit - * to convert - * @return the minimal quantity converted to this unit - */ - public Quantity getMin(Unit unit) { - return min.to(unit); - } - - /** - * Get the maximal amount found within this summary. - * - * @return the maximal quantity - */ - public Quantity getMax() { - return max; - } - - /** - * Get the maximal amount found within this summary converted to unit - * - * @param unit - * to convert - * @return the maximal quantity converted to this unit - */ - public Quantity getMax(Unit unit) { - return max.to(unit); - } - - /** - * Get the sum of all amounts within this summary. - * - * @return the total amount - */ - public Quantity getSum() { - return sum; - } - - /** - * Get the sum of all amounts within this summary converted to unit - * - * @param unit - * to convert - * @return the total amount converted to this unit - */ - public Quantity getSum(Unit unit) { - return sum.to(unit); - } - - /** - * Get the quantity average of all amounts added. - * - * @return the quantity average quantity - */ - public Quantity getAverage() { - return average; - } - - /** - * Get the quantity average of all amounts added converted to unit - * - * @param unit - * to convert - * @return the average quantity converted to this unit - */ - public Quantity getAverage(Unit unit) { - return average.to(unit); - } - - /** - * convert the summary to this unit measure - * - * @param unit - * to convert the summary - * @return the summary converted to this unit - */ - public QuantitySummaryStatistics to(Unit unit) { - QuantitySummaryStatistics summary = new QuantitySummaryStatistics<>(unit); - summary.average = average.to(unit); - summary.count = count; - summary.max = max.to(unit); - summary.min = min.to(unit); - summary.sum = sum.to(unit); - return summary; - } - - /** - * will equals when the unit were equals - */ - @Override - public boolean equals(Object obj) { - if (QuantitySummaryStatistics.class.isInstance(obj)) { - @SuppressWarnings("rawtypes") - QuantitySummaryStatistics other = QuantitySummaryStatistics.class.cast(obj); - return Objects.equals(empty.getUnit(), other.empty.getUnit()); - } - return false; - } - - @Override - public int hashCode() { - return empty.getUnit().hashCode(); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("[currency: ").append(empty.getUnit()).append(","); - sb.append("count:").append(count).append(","); - sb.append("min:").append(min).append(","); - sb.append("max:").append(max).append(","); - sb.append("sum:").append(sum).append(","); - sb.append("average:").append(average).append("]"); - return sb.toString(); - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import java.util.Objects; +import java.util.function.BinaryOperator; + +import javax.measure.Quantity; +import javax.measure.Unit; + +import tec.uom.se.quantity.Quantities; + +/** + * @author Otavio + * @author Werner + * @version 1.0 + * @since 1.0 + * @param + */ +public class QuantitySummaryStatistics> { + + private final Quantity empty; + + private long count; + + private Quantity min; + + private Quantity max; + + private Quantity sum; + + private Quantity average; + + private final BinaryOperator> minFunctions = QuantityFunctions.min(); + + private final BinaryOperator> maxFunctions = QuantityFunctions.max(); + + /** + * Creates a new instance, targeting the given {@link javax.measure.Unit}. + * + * @param unit + * the target unit, not null. + */ + QuantitySummaryStatistics(Unit unit) { + empty = Quantities.getQuantity(0, unit); + setQuantity(empty); + } + + /** + * Records another value into the summary information. + * + * @param quantity + * the input quantity value to be added, not null. + */ + public void accept(Quantity quantity) { + + Objects.requireNonNull(quantity); + + if (isEmpty()) { + setQuantity(quantity.to(empty.getUnit())); + count++; + } else { + doSummary(quantity.to(empty.getUnit())); + } + } + + /** + * Combines the state of another {@code QuantitySummaryStatistics} into this one. + * + * @param quantitySummary + * another {@code QuantitySummaryStatistics}, not null. + */ + public QuantitySummaryStatistics combine(QuantitySummaryStatistics quantitySummary) { + Objects.requireNonNull(quantitySummary); + + if (!equals(quantitySummary)) { + return this; + } + + min = minFunctions.apply(min, quantitySummary.min.to(empty.getUnit())); + max = maxFunctions.apply(max, quantitySummary.max.to(empty.getUnit())); + sum = sum.add(quantitySummary.sum); + count += quantitySummary.count; + average = sum.divide(count); + return this; + } + + private void doSummary(Quantity moneraty) { + min = minFunctions.apply(min, moneraty); + max = maxFunctions.apply(max, moneraty); + sum = sum.add(moneraty); + average = sum.divide(++count); + } + + private boolean isEmpty() { + return count == 0; + } + + private void setQuantity(Quantity quantity) { + min = quantity; + max = quantity; + sum = quantity; + average = quantity; + } + + /** + * Get the number of items added to this summary instance. + * + * @return the number of summarized items, >= 0. + */ + public long getCount() { + return count; + } + + /** + * Get the minimal quantity found within this summary. + * + * @return the minimal quantity + */ + public Quantity getMin() { + return min; + } + + /** + * Get the minimal quantity found within this summary converted to unit + * + * @param unit + * to convert + * @return the minimal quantity converted to this unit + */ + public Quantity getMin(Unit unit) { + return min.to(unit); + } + + /** + * Get the maximal amount found within this summary. + * + * @return the maximal quantity + */ + public Quantity getMax() { + return max; + } + + /** + * Get the maximal amount found within this summary converted to unit + * + * @param unit + * to convert + * @return the maximal quantity converted to this unit + */ + public Quantity getMax(Unit unit) { + return max.to(unit); + } + + /** + * Get the sum of all amounts within this summary. + * + * @return the total amount + */ + public Quantity getSum() { + return sum; + } + + /** + * Get the sum of all amounts within this summary converted to unit + * + * @param unit + * to convert + * @return the total amount converted to this unit + */ + public Quantity getSum(Unit unit) { + return sum.to(unit); + } + + /** + * Get the quantity average of all amounts added. + * + * @return the quantity average quantity + */ + public Quantity getAverage() { + return average; + } + + /** + * Get the quantity average of all amounts added converted to unit + * + * @param unit + * to convert + * @return the average quantity converted to this unit + */ + public Quantity getAverage(Unit unit) { + return average.to(unit); + } + + /** + * convert the summary to this unit measure + * + * @param unit + * to convert the summary + * @return the summary converted to this unit + */ + public QuantitySummaryStatistics to(Unit unit) { + QuantitySummaryStatistics summary = new QuantitySummaryStatistics<>(unit); + summary.average = average.to(unit); + summary.count = count; + summary.max = max.to(unit); + summary.min = min.to(unit); + summary.sum = sum.to(unit); + return summary; + } + + /** + * will equals when the unit were equals + */ + @Override + public boolean equals(Object obj) { + if (QuantitySummaryStatistics.class.isInstance(obj)) { + @SuppressWarnings("rawtypes") + QuantitySummaryStatistics other = QuantitySummaryStatistics.class.cast(obj); + return Objects.equals(empty.getUnit(), other.empty.getUnit()); + } + return false; + } + + @Override + public int hashCode() { + return empty.getUnit().hashCode(); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("[currency: ").append(empty.getUnit()).append(","); + sb.append("count:").append(count).append(","); + sb.append("min:").append(min).append(","); + sb.append("max:").append(max).append(","); + sb.append("sum:").append(sum).append(","); + sb.append("average:").append(average).append("]"); + return sb.toString(); + } +} diff --git a/src/main/java/tec/uom/se/function/RationalConverter.java b/src/main/java/tec/uom/se/function/RationalConverter.java index 5a6bff04..7d9ee783 100644 --- a/src/main/java/tec/uom/se/function/RationalConverter.java +++ b/src/main/java/tec/uom/se/function/RationalConverter.java @@ -1,255 +1,255 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.function; - -import javax.measure.UnitConverter; - -import tec.uom.lib.common.function.ValueSupplier; -import tec.uom.se.AbstractConverter; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; -import java.util.Objects; -import java.util.function.DoubleSupplier; -import java.util.function.Supplier; - -/** - *

- * This class represents a converter multiplying numeric values by an exact scaling factor (represented as the quotient of two BigInteger - * numbers). - *

- * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 1.0, Oct 11, 2016 - * @since 1.0 - */ -public final class RationalConverter extends AbstractConverter implements ValueSupplier, Supplier, DoubleSupplier { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.function; + +import javax.measure.UnitConverter; + +import tec.uom.lib.common.function.ValueSupplier; +import tec.uom.se.AbstractConverter; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.util.Objects; +import java.util.function.DoubleSupplier; +import java.util.function.Supplier; + +/** + *

+ * This class represents a converter multiplying numeric values by an exact scaling factor (represented as the quotient of two BigInteger + * numbers). + *

+ * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 1.0, Oct 11, 2016 + * @since 1.0 + */ +public final class RationalConverter extends AbstractConverter implements ValueSupplier, Supplier, DoubleSupplier { + /** * - */ - private static final long serialVersionUID = 3563384008357680074L; - - /** - * Holds the converter dividend. - */ - private final BigInteger dividend; - - /** - * Holds the converter divisor (always positive). - */ - private final BigInteger divisor; - - /** - * Creates a rational converter with the specified dividend and divisor. - * - * @param dividend - * the dividend. - * @param divisor - * the positive divisor. - * @throws IllegalArgumentException - * if divisor <= 0 - * @throws IllegalArgumentException - * if dividend == divisor - */ - public RationalConverter(BigInteger dividend, BigInteger divisor) { - if (divisor.compareTo(BigInteger.ZERO) <= 0) - throw new IllegalArgumentException("Negative or zero divisor"); - if (dividend.equals(divisor)) - throw new IllegalArgumentException("Would result in identity converter"); - this.dividend = dividend; // Exact conversion. - this.divisor = divisor; // Exact conversion. - } - - /** - * Convenience method equivalent to new RationalConverter(BigInteger.valueOf(dividend), BigInteger.valueOf(divisor)) - * - * @param dividend - * the dividend. - * @param divisor - * the positive divisor. - * @throws IllegalArgumentException - * if divisor <= 0 - * @throws IllegalArgumentException - * if dividend == divisor - */ - public RationalConverter(long dividend, long divisor) { - this(BigInteger.valueOf(dividend), BigInteger.valueOf(divisor)); - } - - /** - * Convenience method equivalent to new RationalConverter(dividend, divisor) - * - * @param dividend - * the dividend. - * @param divisor - * the positive divisor. - * @throws IllegalArgumentException - * if divisor <= 0 - * @throws IllegalArgumentException - * if dividend == divisor - */ - public static RationalConverter of(BigInteger dividend, BigInteger divisor) { - return new RationalConverter(dividend, divisor); - } - - /** - * Convenience method equivalent to new RationalConverter(dividend, divisor) - * - * @param dividend - * the dividend. - * @param divisor - * the positive divisor. - * @throws IllegalArgumentException - * if divisor <= 0 - * @throws IllegalArgumentException - * if dividend == divisor - */ - public static RationalConverter of(long dividend, long divisor) { - return new RationalConverter(dividend, divisor); - } - - /** + */ + private static final long serialVersionUID = 3563384008357680074L; + + /** + * Holds the converter dividend. + */ + private final BigInteger dividend; + + /** + * Holds the converter divisor (always positive). + */ + private final BigInteger divisor; + + /** + * Creates a rational converter with the specified dividend and divisor. + * + * @param dividend + * the dividend. + * @param divisor + * the positive divisor. + * @throws IllegalArgumentException + * if divisor <= 0 + * @throws IllegalArgumentException + * if dividend == divisor + */ + public RationalConverter(BigInteger dividend, BigInteger divisor) { + if (divisor.compareTo(BigInteger.ZERO) <= 0) + throw new IllegalArgumentException("Negative or zero divisor"); + if (dividend.equals(divisor)) + throw new IllegalArgumentException("Would result in identity converter"); + this.dividend = dividend; // Exact conversion. + this.divisor = divisor; // Exact conversion. + } + + /** + * Convenience method equivalent to new RationalConverter(BigInteger.valueOf(dividend), BigInteger.valueOf(divisor)) + * + * @param dividend + * the dividend. + * @param divisor + * the positive divisor. + * @throws IllegalArgumentException + * if divisor <= 0 + * @throws IllegalArgumentException + * if dividend == divisor + */ + public RationalConverter(long dividend, long divisor) { + this(BigInteger.valueOf(dividend), BigInteger.valueOf(divisor)); + } + + /** + * Convenience method equivalent to new RationalConverter(dividend, divisor) + * + * @param dividend + * the dividend. + * @param divisor + * the positive divisor. + * @throws IllegalArgumentException + * if divisor <= 0 + * @throws IllegalArgumentException + * if dividend == divisor + */ + public static RationalConverter of(BigInteger dividend, BigInteger divisor) { + return new RationalConverter(dividend, divisor); + } + + /** + * Convenience method equivalent to new RationalConverter(dividend, divisor) + * + * @param dividend + * the dividend. + * @param divisor + * the positive divisor. + * @throws IllegalArgumentException + * if divisor <= 0 + * @throws IllegalArgumentException + * if dividend == divisor + */ + public static RationalConverter of(long dividend, long divisor) { + return new RationalConverter(dividend, divisor); + } + + /** * Convenience method equivalent to new RationalConverter(BigDecimal.valueOf(dividend).toBigInteger(), - * BigDecimal.valueOf(divisor).toBigInteger()) - * - * @param dividend - * the dividend. - * @param divisor - * the positive divisor. - * @throws IllegalArgumentException - * if divisor <= 0 - * @throws IllegalArgumentException - * if dividend == divisor - */ - public static RationalConverter of(double dividend, double divisor) { - return new RationalConverter(BigDecimal.valueOf(dividend).toBigInteger(), BigDecimal.valueOf(divisor).toBigInteger()); - } - - /** - * Returns the integer dividend for this rational converter. - * - * @return this converter dividend. - */ - public BigInteger getDividend() { - return dividend; - } - - /** - * Returns the integer (positive) divisor for this rational converter. - * - * @return this converter divisor. - */ - public BigInteger getDivisor() { - return divisor; - } - - @Override - public double convert(double value) { - return value * toDouble(dividend) / toDouble(divisor); - } - - // Optimization of BigInteger.doubleValue() (implementation too - // inneficient). - private static double toDouble(BigInteger integer) { - return (integer.bitLength() < 64) ? integer.longValue() : integer.doubleValue(); - } - - @Override - public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { - BigDecimal decimalDividend = new BigDecimal(dividend, 0); - BigDecimal decimalDivisor = new BigDecimal(divisor, 0); - return value.multiply(decimalDividend, ctx).divide(decimalDivisor, ctx); - } - - @Override - public UnitConverter concatenate(UnitConverter converter) { - if (!(converter instanceof RationalConverter)) - return super.concatenate(converter); - RationalConverter that = (RationalConverter) converter; - BigInteger newDividend = this.getDividend().multiply(that.getDividend()); - BigInteger newDivisor = this.getDivisor().multiply(that.getDivisor()); - BigInteger gcd = newDividend.gcd(newDivisor); - newDividend = newDividend.divide(gcd); - newDivisor = newDivisor.divide(gcd); - return (newDividend.equals(BigInteger.ONE) && newDivisor.equals(BigInteger.ONE)) ? IDENTITY : new RationalConverter(newDividend, newDivisor); - } - - @Override - public RationalConverter inverse() { - return dividend.signum() == -1 ? new RationalConverter(getDivisor().negate(), getDividend().negate()) : new RationalConverter(getDivisor(), - getDividend()); - } - - @Override - public final String toString() { - return "RationalConverter(" + dividend + "," + divisor + ")"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof RationalConverter) { - - RationalConverter that = (RationalConverter) obj; - return Objects.equals(dividend, that.dividend) && Objects.equals(divisor, that.divisor); - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(dividend, divisor); - } - - @Override - public boolean isLinear() { - return true; - } - - @Override - public Double getValue() { - return getAsDouble(); - } - - @Override - public double getAsDouble() { - return toDouble(dividend) / toDouble(divisor); - } - - @Override - public Double get() { - return getValue(); - } -} + * BigDecimal.valueOf(divisor).toBigInteger()) + * + * @param dividend + * the dividend. + * @param divisor + * the positive divisor. + * @throws IllegalArgumentException + * if divisor <= 0 + * @throws IllegalArgumentException + * if dividend == divisor + */ + public static RationalConverter of(double dividend, double divisor) { + return new RationalConverter(BigDecimal.valueOf(dividend).toBigInteger(), BigDecimal.valueOf(divisor).toBigInteger()); + } + + /** + * Returns the integer dividend for this rational converter. + * + * @return this converter dividend. + */ + public BigInteger getDividend() { + return dividend; + } + + /** + * Returns the integer (positive) divisor for this rational converter. + * + * @return this converter divisor. + */ + public BigInteger getDivisor() { + return divisor; + } + + @Override + public double convert(double value) { + return value * toDouble(dividend) / toDouble(divisor); + } + + // Optimization of BigInteger.doubleValue() (implementation too + // inneficient). + private static double toDouble(BigInteger integer) { + return (integer.bitLength() < 64) ? integer.longValue() : integer.doubleValue(); + } + + @Override + public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException { + BigDecimal decimalDividend = new BigDecimal(dividend, 0); + BigDecimal decimalDivisor = new BigDecimal(divisor, 0); + return value.multiply(decimalDividend, ctx).divide(decimalDivisor, ctx); + } + + @Override + public UnitConverter concatenate(UnitConverter converter) { + if (!(converter instanceof RationalConverter)) + return super.concatenate(converter); + RationalConverter that = (RationalConverter) converter; + BigInteger newDividend = this.getDividend().multiply(that.getDividend()); + BigInteger newDivisor = this.getDivisor().multiply(that.getDivisor()); + BigInteger gcd = newDividend.gcd(newDivisor); + newDividend = newDividend.divide(gcd); + newDivisor = newDivisor.divide(gcd); + return (newDividend.equals(BigInteger.ONE) && newDivisor.equals(BigInteger.ONE)) ? IDENTITY : new RationalConverter(newDividend, newDivisor); + } + + @Override + public RationalConverter inverse() { + return dividend.signum() == -1 ? new RationalConverter(getDivisor().negate(), getDividend().negate()) : new RationalConverter(getDivisor(), + getDividend()); + } + + @Override + public final String toString() { + return "RationalConverter(" + dividend + "," + divisor + ")"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof RationalConverter) { + + RationalConverter that = (RationalConverter) obj; + return Objects.equals(dividend, that.dividend) && Objects.equals(divisor, that.divisor); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(dividend, divisor); + } + + @Override + public boolean isLinear() { + return true; + } + + @Override + public Double getValue() { + return getAsDouble(); + } + + @Override + public double getAsDouble() { + return toDouble(dividend) / toDouble(divisor); + } + + @Override + public Double get() { + return getValue(); + } +} diff --git a/src/main/java/tec/uom/se/function/package-info.java b/src/main/java/tec/uom/se/function/package-info.java index 7586b858..634c00f9 100644 --- a/src/main/java/tec/uom/se/function/package-info.java +++ b/src/main/java/tec/uom/se/function/package-info.java @@ -1,35 +1,35 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/** - * This package provides functional interfaces. - */ -package tec.uom.se.function; - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * This package provides functional interfaces. + */ +package tec.uom.se.function; + diff --git a/src/main/java/tec/uom/se/internal/DefaultSystemOfUnitsService.java b/src/main/java/tec/uom/se/internal/DefaultSystemOfUnitsService.java index 9ce4f423..f295d7ff 100644 --- a/src/main/java/tec/uom/se/internal/DefaultSystemOfUnitsService.java +++ b/src/main/java/tec/uom/se/internal/DefaultSystemOfUnitsService.java @@ -1,67 +1,67 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.internal; - -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import javax.measure.spi.SystemOfUnits; -import javax.measure.spi.SystemOfUnitsService; - -import tec.uom.se.unit.Units; - -/** - * @author Werner Keil - * @version 0.2, November 3, 2015 - */ -public class DefaultSystemOfUnitsService implements SystemOfUnitsService { - - final Map souMap = new ConcurrentHashMap<>(); - - public DefaultSystemOfUnitsService() { - souMap.put(Units.class.getSimpleName(), Units.getInstance()); - } - - public Collection getAvailableSystemsOfUnits() { - return souMap.values(); - } - - @Override - public SystemOfUnits getSystemOfUnits() { - return getSystemOfUnits(Units.class.getSimpleName()); - } - - @Override - public SystemOfUnits getSystemOfUnits(String name) { - return souMap.get(name); - } - -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.internal; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.measure.spi.SystemOfUnits; +import javax.measure.spi.SystemOfUnitsService; + +import tec.uom.se.unit.Units; + +/** + * @author Werner Keil + * @version 0.2, November 3, 2015 + */ +public class DefaultSystemOfUnitsService implements SystemOfUnitsService { + + final Map souMap = new ConcurrentHashMap<>(); + + public DefaultSystemOfUnitsService() { + souMap.put(Units.class.getSimpleName(), Units.getInstance()); + } + + public Collection getAvailableSystemsOfUnits() { + return souMap.values(); + } + + @Override + public SystemOfUnits getSystemOfUnits() { + return getSystemOfUnits(Units.class.getSimpleName()); + } + + @Override + public SystemOfUnits getSystemOfUnits(String name) { + return souMap.get(name); + } + +} diff --git a/src/main/java/tec/uom/se/internal/format/DefaultCharStream.java b/src/main/java/tec/uom/se/internal/format/DefaultCharStream.java index 796d942f..5dd11ca2 100644 --- a/src/main/java/tec/uom/se/internal/format/DefaultCharStream.java +++ b/src/main/java/tec/uom/se/internal/format/DefaultCharStream.java @@ -1,441 +1,441 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. DefaultCharStream.java Version 5.0 */ -/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ -package tec.uom.se.internal.format; - -/** - * An implementation of interface CharStream, where the stream is assumed to contain only ASCII characters (without unicode processing). - * - * @version 5.1, December 25, 2013 - */ - -final class DefaultCharStream { - /** Whether parser is static. */ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - /** Position in buffer. */ - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - protected int tabSize = 8; - - protected void setTabSize(int i) { - tabSize = i; - } - - protected int getTabSize() { - return tabSize; - } - - protected void ExpandBuff(boolean wrapAround) { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try { - if (wrapAround) { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } else { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } catch (Throwable t) { - throw new Error(t.getMessage()); - } - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException { - if (maxNextCharInd == available) { - if (available == bufsize) { - if (tokenBegin > 2048) { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { - inputStream.close(); - throw new java.io.IOException(); - } else - maxNextCharInd += i; - } catch (java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - /** Start. */ - public char BeginToken() throws java.io.IOException { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) { - column++; - - if (prevCharIsLF) { - prevCharIsLF = false; - line += (column = 1); - } else if (prevCharIsCR) { - prevCharIsCR = false; - if (c == '\n') { - prevCharIsLF = true; - } else - line += (column = 1); - } - - switch (c) { - case '\r': - prevCharIsCR = true; - break; - case '\n': - prevCharIsLF = true; - break; - case '\t': - column--; - column += (tabSize - (column % tabSize)); - break; - default: - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - /** Read a character. */ - public char readChar() throws java.io.IOException { - if (inBuf > 0) { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return c; - } - - @Deprecated - /** - * @deprecated - * @see #getEndColumn - */ - public int getColumn() { - return bufcolumn[bufpos]; - } - - @Deprecated - /** - * @deprecated - * @see #getEndLine - */ - public int getLine() { - return bufline[bufpos]; - } - - /** Get token end column number. */ - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - /** Get token end line number. */ - public int getEndLine() { - return bufline[bufpos]; - } - - /** Get token beginning column number. */ - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - /** Get token beginning line number. */ - public int getBeginLine() { - return bufline[tokenBegin]; - } - - /** Backup a number of characters. */ - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - /** Constructor. */ - public DefaultCharStream(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - /** Constructor. */ - public DefaultCharStream(java.io.Reader dstream, int startline, int startcolumn) { - this(dstream, startline, startcolumn, 4096); - } - - /** Constructor. */ - public DefaultCharStream(java.io.Reader dstream) { - this(dstream, 1, 1, 4096); - } - - /** Reinitialise. */ - public void ReInit(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - /** Reinitialise. */ - public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { - ReInit(dstream, startline, startcolumn, 4096); - } - - /** Reinitialise. */ - public void ReInit(java.io.Reader dstream) { - ReInit(dstream, 1, 1, 4096); - } - - /** Constructor. */ - public DefaultCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) - throws java.io.UnsupportedEncodingException { - this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, - buffersize); - } - - /** Constructor. */ - public DefaultCharStream(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - /** Constructor. */ - public DefaultCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { - this(dstream, encoding, startline, startcolumn, 4096); - } - - /** Constructor. */ - public DefaultCharStream(java.io.InputStream dstream, int startline, int startcolumn) { - this(dstream, startline, startcolumn, 4096); - } - - /** Constructor. */ - public DefaultCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { - this(dstream, encoding, 1, 1, 4096); - } - - /** Constructor. */ - public DefaultCharStream(java.io.InputStream dstream) { - this(dstream, 1, 1, 4096); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) - throws java.io.UnsupportedEncodingException { - ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, - buffersize); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { - ReInit(dstream, encoding, 1, 1, 4096); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream dstream) { - ReInit(dstream, 1, 1, 4096); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { - ReInit(dstream, encoding, startline, startcolumn, 4096); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { - ReInit(dstream, startline, startcolumn, 4096); - } - - /** Get token literal value. */ - public String GetImage() { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1); - } - - /** Get the suffix. */ - public char[] GetSuffix(int len) { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - /** Reset buffer when finished. */ - public void Done() { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) { - len = bufpos - tokenBegin + inBuf + 1; - } else { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} -/* - * JavaCC - OriginalChecksum=ec4e178f3ccf05ea2ca32d15e09312ca (do not edit this - * line) - */ +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. DefaultCharStream.java Version 5.0 */ +/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ +package tec.uom.se.internal.format; + +/** + * An implementation of interface CharStream, where the stream is assumed to contain only ASCII characters (without unicode processing). + * + * @version 5.1, December 25, 2013 + */ + +final class DefaultCharStream { + /** Whether parser is static. */ + public static final boolean staticFlag = false; + int bufsize; + int available; + int tokenBegin; + /** Position in buffer. */ + public int bufpos = -1; + protected int bufline[]; + protected int bufcolumn[]; + + protected int column = 0; + protected int line = 1; + + protected boolean prevCharIsCR = false; + protected boolean prevCharIsLF = false; + + protected java.io.Reader inputStream; + + protected char[] buffer; + protected int maxNextCharInd = 0; + protected int inBuf = 0; + protected int tabSize = 8; + + protected void setTabSize(int i) { + tabSize = i; + } + + protected int getTabSize() { + return tabSize; + } + + protected void ExpandBuff(boolean wrapAround) { + char[] newbuffer = new char[bufsize + 2048]; + int newbufline[] = new int[bufsize + 2048]; + int newbufcolumn[] = new int[bufsize + 2048]; + + try { + if (wrapAround) { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); + bufcolumn = newbufcolumn; + + maxNextCharInd = (bufpos += (bufsize - tokenBegin)); + } else { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + bufcolumn = newbufcolumn; + + maxNextCharInd = (bufpos -= tokenBegin); + } + } catch (Throwable t) { + throw new Error(t.getMessage()); + } + + bufsize += 2048; + available = bufsize; + tokenBegin = 0; + } + + protected void FillBuff() throws java.io.IOException { + if (maxNextCharInd == available) { + if (available == bufsize) { + if (tokenBegin > 2048) { + bufpos = maxNextCharInd = 0; + available = tokenBegin; + } else if (tokenBegin < 0) + bufpos = maxNextCharInd = 0; + else + ExpandBuff(false); + } else if (available > tokenBegin) + available = bufsize; + else if ((tokenBegin - available) < 2048) + ExpandBuff(true); + else + available = tokenBegin; + } + + int i; + try { + if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { + inputStream.close(); + throw new java.io.IOException(); + } else + maxNextCharInd += i; + } catch (java.io.IOException e) { + --bufpos; + backup(0); + if (tokenBegin == -1) + tokenBegin = bufpos; + throw e; + } + } + + /** Start. */ + public char BeginToken() throws java.io.IOException { + tokenBegin = -1; + char c = readChar(); + tokenBegin = bufpos; + + return c; + } + + protected void UpdateLineColumn(char c) { + column++; + + if (prevCharIsLF) { + prevCharIsLF = false; + line += (column = 1); + } else if (prevCharIsCR) { + prevCharIsCR = false; + if (c == '\n') { + prevCharIsLF = true; + } else + line += (column = 1); + } + + switch (c) { + case '\r': + prevCharIsCR = true; + break; + case '\n': + prevCharIsLF = true; + break; + case '\t': + column--; + column += (tabSize - (column % tabSize)); + break; + default: + break; + } + + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + + /** Read a character. */ + public char readChar() throws java.io.IOException { + if (inBuf > 0) { + --inBuf; + + if (++bufpos == bufsize) + bufpos = 0; + + return buffer[bufpos]; + } + + if (++bufpos >= maxNextCharInd) + FillBuff(); + + char c = buffer[bufpos]; + + UpdateLineColumn(c); + return c; + } + + @Deprecated + /** + * @deprecated + * @see #getEndColumn + */ + public int getColumn() { + return bufcolumn[bufpos]; + } + + @Deprecated + /** + * @deprecated + * @see #getEndLine + */ + public int getLine() { + return bufline[bufpos]; + } + + /** Get token end column number. */ + public int getEndColumn() { + return bufcolumn[bufpos]; + } + + /** Get token end line number. */ + public int getEndLine() { + return bufline[bufpos]; + } + + /** Get token beginning column number. */ + public int getBeginColumn() { + return bufcolumn[tokenBegin]; + } + + /** Get token beginning line number. */ + public int getBeginLine() { + return bufline[tokenBegin]; + } + + /** Backup a number of characters. */ + public void backup(int amount) { + + inBuf += amount; + if ((bufpos -= amount) < 0) + bufpos += bufsize; + } + + /** Constructor. */ + public DefaultCharStream(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + + /** Constructor. */ + public DefaultCharStream(java.io.Reader dstream, int startline, int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + /** Constructor. */ + public DefaultCharStream(java.io.Reader dstream) { + this(dstream, 1, 1, 4096); + } + + /** Reinitialise. */ + public void ReInit(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + if (buffer == null || buffersize != buffer.length) { + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + prevCharIsLF = prevCharIsCR = false; + tokenBegin = inBuf = maxNextCharInd = 0; + bufpos = -1; + } + + /** Reinitialise. */ + public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + /** Reinitialise. */ + public void ReInit(java.io.Reader dstream) { + ReInit(dstream, 1, 1, 4096); + } + + /** Constructor. */ + public DefaultCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) + throws java.io.UnsupportedEncodingException { + this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, + buffersize); + } + + /** Constructor. */ + public DefaultCharStream(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { + this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); + } + + /** Constructor. */ + public DefaultCharStream(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, startline, startcolumn, 4096); + } + + /** Constructor. */ + public DefaultCharStream(java.io.InputStream dstream, int startline, int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + /** Constructor. */ + public DefaultCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + this(dstream, encoding, 1, 1, 4096); + } + + /** Constructor. */ + public DefaultCharStream(java.io.InputStream dstream) { + this(dstream, 1, 1, 4096); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn, int buffersize) + throws java.io.UnsupportedEncodingException { + ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, + buffersize); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, 1, 1, 4096); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream dstream) { + ReInit(dstream, 1, 1, 4096); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream dstream, String encoding, int startline, int startcolumn) throws java.io.UnsupportedEncodingException { + ReInit(dstream, encoding, startline, startcolumn, 4096); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { + ReInit(dstream, startline, startcolumn, 4096); + } + + /** Get token literal value. */ + public String GetImage() { + if (bufpos >= tokenBegin) + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); + else + return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1); + } + + /** Get the suffix. */ + public char[] GetSuffix(int len) { + char[] ret = new char[len]; + + if ((bufpos + 1) >= len) + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); + else { + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); + } + + return ret; + } + + /** Reset buffer when finished. */ + public void Done() { + buffer = null; + bufline = null; + bufcolumn = null; + } + + /** + * Method to adjust line and column numbers for the start of a token. + */ + public void adjustBeginLineColumn(int newLine, int newCol) { + int start = tokenBegin; + int len; + + if (bufpos >= tokenBegin) { + len = bufpos - tokenBegin + inBuf + 1; + } else { + len = bufsize - tokenBegin + bufpos + 1 + inBuf; + } + + int i = 0, j = 0, k = 0; + int nextColDiff = 0, columnDiff = 0; + + while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { + bufline[j] = newLine; + nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; + bufcolumn[j] = newCol + columnDiff; + columnDiff = nextColDiff; + i++; + } + + if (i < len) { + bufline[j] = newLine++; + bufcolumn[j] = newCol + columnDiff; + + while (i++ < len) { + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) + bufline[j] = newLine++; + else + bufline[j] = newLine; + } + } + + line = bufline[j]; + column = bufcolumn[j]; + } + +} +/* + * JavaCC - OriginalChecksum=ec4e178f3ccf05ea2ca32d15e09312ca (do not edit this + * line) + */ diff --git a/src/main/java/tec/uom/se/internal/format/DefaultUnitFormatService.java b/src/main/java/tec/uom/se/internal/format/DefaultUnitFormatService.java index 0b36792e..1b4fcaeb 100644 --- a/src/main/java/tec/uom/se/internal/format/DefaultUnitFormatService.java +++ b/src/main/java/tec/uom/se/internal/format/DefaultUnitFormatService.java @@ -1,95 +1,95 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.internal.format; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import javax.measure.format.UnitFormat; -import javax.measure.spi.UnitFormatService; - -import tec.uom.lib.common.function.IntPrioritySupplier; -import tec.uom.se.format.EBNFUnitFormat; -import tec.uom.se.format.LocalUnitFormat; -import tec.uom.se.format.SimpleUnitFormat; -import tec.uom.se.format.SimpleUnitFormat.Flavor; - -/** - * Default format service. - * - * @author Werner Keil - * @version 0.5, January 19, 2017 - */ -public class DefaultUnitFormatService implements UnitFormatService, IntPrioritySupplier { - static final int PRIO = 1000; - - private static final String DEFAULT_FORMAT = Flavor.Default.name(); - - private final Map formats = new HashMap<>(); - - public DefaultUnitFormatService() { - formats.put(DEFAULT_FORMAT, SimpleUnitFormat.getInstance()); - formats.put(Flavor.ASCII.name(), SimpleUnitFormat.getInstance(Flavor.ASCII)); - formats.put("EBNF", EBNFUnitFormat.getInstance()); - formats.put("Local", LocalUnitFormat.getInstance()); - } - - /* - * (non-Javadoc) - * - * @see UnitFormatService#getUnitFormat(String) - */ - @Override - public UnitFormat getUnitFormat(String formatName) { - Objects.requireNonNull(formatName, "Format name required"); - return formats.get(formatName); - } - - /* - * (non-Javadoc) - * - * @see UnitFormatService#getUnitFormat() - */ - @Override - public UnitFormat getUnitFormat() { - return getUnitFormat(DEFAULT_FORMAT); - } - - public Set getAvailableFormatNames() { - return formats.keySet(); - } - - @Override - public int getPriority() { - return PRIO; - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.internal.format; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import javax.measure.format.UnitFormat; +import javax.measure.spi.UnitFormatService; + +import tec.uom.lib.common.function.IntPrioritySupplier; +import tec.uom.se.format.EBNFUnitFormat; +import tec.uom.se.format.LocalUnitFormat; +import tec.uom.se.format.SimpleUnitFormat; +import tec.uom.se.format.SimpleUnitFormat.Flavor; + +/** + * Default format service. + * + * @author Werner Keil + * @version 0.5, January 19, 2017 + */ +public class DefaultUnitFormatService implements UnitFormatService, IntPrioritySupplier { + static final int PRIO = 1000; + + private static final String DEFAULT_FORMAT = Flavor.Default.name(); + + private final Map formats = new HashMap<>(); + + public DefaultUnitFormatService() { + formats.put(DEFAULT_FORMAT, SimpleUnitFormat.getInstance()); + formats.put(Flavor.ASCII.name(), SimpleUnitFormat.getInstance(Flavor.ASCII)); + formats.put("EBNF", EBNFUnitFormat.getInstance()); + formats.put("Local", LocalUnitFormat.getInstance()); + } + + /* + * (non-Javadoc) + * + * @see UnitFormatService#getUnitFormat(String) + */ + @Override + public UnitFormat getUnitFormat(String formatName) { + Objects.requireNonNull(formatName, "Format name required"); + return formats.get(formatName); + } + + /* + * (non-Javadoc) + * + * @see UnitFormatService#getUnitFormat() + */ + @Override + public UnitFormat getUnitFormat() { + return getUnitFormat(DEFAULT_FORMAT); + } + + public Set getAvailableFormatNames() { + return formats.keySet(); + } + + @Override + public int getPriority() { + return PRIO; + } +} diff --git a/src/main/java/tec/uom/se/internal/format/LocalUnitFormatParser.java b/src/main/java/tec/uom/se/internal/format/LocalUnitFormatParser.java index c4b68cfa..8bf91349 100644 --- a/src/main/java/tec/uom/se/internal/format/LocalUnitFormatParser.java +++ b/src/main/java/tec/uom/se/internal/format/LocalUnitFormatParser.java @@ -1,905 +1,905 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. LocalUnitFormatParser.java */ -package tec.uom.se.internal.format; - -import static tec.uom.se.internal.format.UnitTokenConstants.*; - -import javax.measure.Unit; - -import tec.uom.se.AbstractUnit; -import tec.uom.se.format.SymbolMap; -import tec.uom.se.function.LogConverter; -import tec.uom.se.unit.MetricPrefix; - -/** - * @deprecated use {@link UnitFormatParser} FIXME there are some details e.g. Exception handling that are different, try to resolve or keep LUFP - */ -@SuppressWarnings({ "rawtypes", "unchecked" }) -public final class LocalUnitFormatParser { - - private static class Exponent { - - public final int pow; - - public final int root; - - public Exponent(int pow, int root) { - this.pow = pow; - this.root = root; - } - } - - private SymbolMap symbols; - - public LocalUnitFormatParser(SymbolMap symbols, java.io.Reader in) { - this(in); - this.symbols = symbols; - } - - final public Unit parseUnit() throws TokenException { - Unit result = CompoundExpr(); - consumeToken(0); - { - return result; - } - } - - final public Unit CompoundExpr() throws TokenException { - throw new UnsupportedOperationException("Compound units not supported"); - } - - final public Unit AddExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Number n1 = null; - Token sign1 = null; - Number n2 = null; - Token sign2 = null; - if (jj_2_1(2147483647)) { - n1 = NumberExpr(); - sign1 = Sign(); - } else { - } - result = MulExpr(); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case PLUS: - case MINUS: - sign2 = Sign(); - n2 = NumberExpr(); - break; - default: - laA[1] = genInt; - } - if (n1 != null) { - if (sign1.image.equals("-")) { - result = result.multiply(-1); - } - result = result.shift(n1.doubleValue()); - } - if (n2 != null) { - double offset = n2.doubleValue(); - if (sign2.image.equals("-")) { - offset = -offset; - } - result = result.shift(offset); - } - { - return result; - } - } - - final public Unit MulExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Unit temp = AbstractUnit.ONE; - result = ExponentExpr(); - label_2: while (true) { - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case ASTERISK: - case MIDDLE_DOT: - case SOLIDUS: - break; - default: - laA[2] = genInt; - break label_2; - } - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case ASTERISK: - case MIDDLE_DOT: - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case ASTERISK: - consumeToken(ASTERISK); - break; - case MIDDLE_DOT: - consumeToken(MIDDLE_DOT); - break; - default: - laA[3] = genInt; - consumeToken(-1); - throw new TokenException(); - } - temp = ExponentExpr(); - result = result.multiply(temp); - break; - case SOLIDUS: - consumeToken(SOLIDUS); - temp = ExponentExpr(); - result = result.divide(temp); - break; - default: - laA[4] = genInt; - consumeToken(-1); - throw new TokenException(); - } - } - { - return result; - } - } - - final public Unit ExponentExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Exponent exponent = null; - Token token = null; - if (jj_2_2(2147483647)) { - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case INTEGER: - token = consumeToken(INTEGER); - break; - case E: - token = consumeToken(E); - break; - default: - laA[5] = genInt; - consumeToken(-1); - throw new TokenException(); - } - consumeToken(CARET); - result = AtomicExpr(); - double base; - if (token.kind == INTEGER) { - base = Integer.parseInt(token.image); - } else { - base = StrictMath.E; - } - { - return result.transform(new LogConverter(base).inverse()); - } - } else { - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case OPEN_PAREN: - case INTEGER: - case FLOATING_POINT: - case UNIT_IDENTIFIER: - result = AtomicExpr(); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case CARET: - case SUPERSCRIPT_INTEGER: - exponent = Exp(); - break; - default: - laA[6] = genInt; - } - if (exponent != null) { - if (exponent.pow != 1) { - result = result.pow(exponent.pow); - } - if (exponent.root != 1) { - result = result.root(exponent.root); - } - } - { - return result; - } - case LOG: - case NAT_LOG: - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case LOG: - consumeToken(LOG); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case INTEGER: - token = consumeToken(INTEGER); - break; - default: - laA[7] = genInt; - } - break; - case NAT_LOG: - token = consumeToken(NAT_LOG); - break; - default: - laA[8] = genInt; - consumeToken(-1); - throw new TokenException(); - } - consumeToken(OPEN_PAREN); - result = AddExpr(); - consumeToken(CLOSE_PAREN); - double base = 10; - if (token != null) { - if (token.kind == INTEGER) { - base = Integer.parseInt(token.image); - } else if (token.kind == NAT_LOG) { - base = StrictMath.E; - } - } - { - return result.transform(new LogConverter(base)); - } - default: - laA[9] = genInt; - consumeToken(-1); - throw new TokenException(); - } - } - } - - final public Unit AtomicExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Number n = null; - Token token = null; - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case INTEGER: - case FLOATING_POINT: - n = NumberExpr(); - if (n instanceof Integer) { - { - return result.multiply(n.intValue()); - } - } else { - { - return result.multiply(n.doubleValue()); - } - } - case UNIT_IDENTIFIER: - token = consumeToken(UNIT_IDENTIFIER); - Unit unit = symbols.getUnit(token.image); - if (unit == null) { - MetricPrefix prefix = symbols.getPrefix(token.image); - if (prefix != null) { - String prefixSymbol = symbols.getSymbol(prefix); - unit = symbols.getUnit(token.image.substring(prefixSymbol.length())); - if (unit != null) { - { - return unit.transform(prefix.getConverter()); - } - } - } - { - throw new TokenException(); - } - } else { - { - return unit; - } - } - case OPEN_PAREN: - consumeToken(OPEN_PAREN); - result = AddExpr(); - consumeToken(CLOSE_PAREN); - { - return result; - } - default: - laA[10] = genInt; - consumeToken(-1); - throw new TokenException(); - } - } - - final public Token Sign() throws TokenException { - Token result = null; - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case PLUS: - result = consumeToken(PLUS); - break; - case MINUS: - result = consumeToken(MINUS); - break; - default: - laA[11] = genInt; - consumeToken(-1); - throw new TokenException(); - } - { - return result; - } - } - - final public Number NumberExpr() throws TokenException { - Token token = null; - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case INTEGER: - token = consumeToken(INTEGER); - { - return Long.valueOf(token.image); - } - case FLOATING_POINT: - token = consumeToken(FLOATING_POINT); - { - return Double.valueOf(token.image); - } - default: - laA[12] = genInt; - consumeToken(-1); - throw new TokenException(); - } - } - - final public Exponent Exp() throws TokenException { - Token powSign = null; - Token powToken = null; - Token rootSign = null; - Token rootToken = null; - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case CARET: - consumeToken(CARET); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case PLUS: - case MINUS: - case INTEGER: - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case PLUS: - case MINUS: - powSign = Sign(); - break; - default: - laA[13] = genInt; - } - powToken = consumeToken(INTEGER); - int pow = Integer.parseInt(powToken.image); - if ((powSign != null) && powSign.image.equals("-")) { - pow = -pow; - } - { - return new Exponent(pow, 1); - } - case OPEN_PAREN: - consumeToken(OPEN_PAREN); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case PLUS: - case MINUS: - powSign = Sign(); - break; - default: - laA[14] = genInt; - } - powToken = consumeToken(INTEGER); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case SOLIDUS: - consumeToken(SOLIDUS); - switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { - case PLUS: - case MINUS: - rootSign = Sign(); - break; - default: - laA[15] = genInt; - } - rootToken = consumeToken(INTEGER); - break; - default: - laA[16] = genInt; - } - consumeToken(CLOSE_PAREN); - pow = Integer.parseInt(powToken.image); - if ((powSign != null) && powSign.image.equals("-")) { - pow = -pow; - } - int root = 1; - if (rootToken != null) { - root = Integer.parseInt(rootToken.image); - if ((rootSign != null) && rootSign.image.equals("-")) { - root = -root; - } - } - { - return new Exponent(pow, root); - } - default: - laA[17] = genInt; - consumeToken(-1); - throw new TokenException(); - } - case SUPERSCRIPT_INTEGER: - powToken = consumeToken(SUPERSCRIPT_INTEGER); - int pow = 0; - for (int i = 0; i < powToken.image.length(); i += 1) { - pow *= 10; - switch (powToken.image.charAt(i)) { - case '\u00b9': - pow += 1; - break; - case '\u00b2': - pow += 2; - break; - case '\u00b3': - pow += 3; - break; - case '\u2074': - pow += 4; - break; - case '\u2075': - pow += 5; - break; - case '\u2076': - pow += 6; - break; - case '\u2077': - pow += 7; - break; - case '\u2078': - pow += 8; - break; - case '\u2079': - pow += 9; - break; - } - } - { - return new Exponent(pow, 1); - } - default: - laA[18] = genInt; - consumeToken(-1); - throw new TokenException(); - } - } - - private boolean jj_2_1(int xla) { - laInt = xla; - lastpos = scanpos = token; - try { - return !jj_3_1(); - } catch (LookaheadSuccess ls) { - return true; - } finally { - jj_save(0, xla); - } - } - - private boolean jj_2_2(int xla) { - laInt = xla; - lastpos = scanpos = token; - try { - return !jj_3_2(); - } catch (LookaheadSuccess ls) { - return true; - } finally { - jj_save(1, xla); - } - } - - private boolean jj_3R_3() { - Token xsp; - xsp = scanpos; - if (jj_3R_5()) { - scanpos = xsp; - if (jj_3R_6()) - return true; - } - return false; - } - - private boolean jj_3R_6() { - return scanToken(FLOATING_POINT); - } - - private boolean jj_3_2() { - Token xsp; - xsp = scanpos; - if (scanToken(14)) { - scanpos = xsp; - if (scanToken(19)) - return true; - } - return scanToken(CARET); - } - - private boolean jj_3_1() { - return jj_3R_3() || jj_3R_4(); - } - - private boolean jj_3R_4() { - Token xsp; - xsp = scanpos; - if (scanToken(5)) { - scanpos = xsp; - if (scanToken(6)) - return true; - } - return false; - } - - private boolean jj_3R_5() { - return scanToken(INTEGER); - } - - /** Generated Token Manager. */ - public UnitTokenManager tokenSource; - - DefaultCharStream inputStream; - - /** Current token. */ - public Token token; - - /** Next token. */ - public Token nextToken; - - private int nextTokenIndex; - - private Token scanpos, lastpos; - - private int laInt; - - private int genInt; - - final private int[] laA = new int[19]; - - static private int[] laB; - - static { - init(); - } - - private static void init() { - laB = new int[] { 0x800, 0x60, 0x380, 0x180, 0x380, 0x84000, 0x8400, 0x4000, 0x60000, 0x175000, 0x115000, 0x60, 0x14000, 0x60, 0x60, 0x60, 0x200, - 0x5060, 0x8400, }; - } - - final private JJCalls[] rtns = new JJCalls[2]; - - private boolean rescan = false; - - private int gcInt = 0; - - /** Constructor with InputStream. */ - public LocalUnitFormatParser(java.io.InputStream stream) { - this(stream, null); - } - - /** Constructor with InputStream and supplied encoding */ - public LocalUnitFormatParser(java.io.InputStream stream, String encoding) { - try { - inputStream = new DefaultCharStream(stream, encoding, 1, 1); - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - tokenSource = new UnitTokenManager(inputStream); - token = new Token(); - nextTokenIndex = -1; - genInt = 0; - for (int i = 0; i < 19; i++) { - laA[i] = -1; - } - for (int i = 0; i < rtns.length; i++) { - rtns[i] = new JJCalls(); - } - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream stream) { - ReInit(stream, null); - } - - /** Reinitialise. */ - public void ReInit(java.io.InputStream stream, String encoding) { - try { - inputStream.ReInit(stream, encoding, 1, 1); - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - tokenSource.ReInit(inputStream); - token = new Token(); - nextTokenIndex = -1; - genInt = 0; - for (int i = 0; i < 19; i++) { - laA[i] = -1; - } - for (int i = 0; i < rtns.length; i++) { - rtns[i] = new JJCalls(); - } - } - - /** Constructor. */ - public LocalUnitFormatParser(java.io.Reader stream) { - inputStream = new DefaultCharStream(stream, 1, 1); - tokenSource = new UnitTokenManager(inputStream); - token = new Token(); - nextTokenIndex = -1; - genInt = 0; - for (int i = 0; i < 19; i++) { - laA[i] = -1; - } - for (int i = 0; i < rtns.length; i++) { - rtns[i] = new JJCalls(); - } - } - - /** Reinitialise. */ - public void ReInit(java.io.Reader stream) { - inputStream.ReInit(stream, 1, 1); - tokenSource.ReInit(inputStream); - token = new Token(); - nextTokenIndex = -1; - genInt = 0; - for (int i = 0; i < 19; i++) { - laA[i] = -1; - } - for (int i = 0; i < rtns.length; i++) { - rtns[i] = new JJCalls(); - } - } - - /** Constructor with generated Token Manager. */ - public LocalUnitFormatParser(UnitTokenManager tm) { - tokenSource = tm; - token = new Token(); - nextTokenIndex = -1; - genInt = 0; - for (int i = 0; i < 19; i++) { - laA[i] = -1; - } - for (int i = 0; i < rtns.length; i++) { - rtns[i] = new JJCalls(); - } - } - - /** Reinitialise. */ - public void ReInit(UnitTokenManager tm) { - tokenSource = tm; - token = new Token(); - nextTokenIndex = -1; - genInt = 0; - for (int i = 0; i < 19; i++) { - laA[i] = -1; - } - for (int i = 0; i < rtns.length; i++) { - rtns[i] = new JJCalls(); - } - } - - private Token consumeToken(int kind) throws TokenException { - Token oldToken; - if ((oldToken = token).next != null) - token = token.next; - else - token = token.next = tokenSource.getNextToken(); - nextTokenIndex = -1; - if (token.kind == kind) { - genInt++; - if (++gcInt > 100) { - gcInt = 0; - for (JJCalls jj_2_rtn : rtns) { - JJCalls c = jj_2_rtn; - while (c != null) { - if (c.gen < genInt) - c.first = null; - c = c.next; - } - } - } - return token; - } - token = oldToken; - this.kind = kind; - throw raiseTokenException(); - } - - static private final class LookaheadSuccess extends java.lang.RuntimeException { - private static final long serialVersionUID = 2205332054119123041L; - } - - private boolean scanToken(int kind) { - if (scanpos == lastpos) { - laInt--; - if (scanpos.next == null) { - lastpos = scanpos = scanpos.next = tokenSource.getNextToken(); - } else { - lastpos = scanpos = scanpos.next; - } - } else { - scanpos = scanpos.next; - } - if (rescan) { - int i = 0; - Token tok = token; - while (tok != null && tok != scanpos) { - i++; - tok = tok.next; - } - if (tok != null) - jj_add_error_token(kind, i); - } - if (scanpos.kind != kind) - return true; - if (laInt == 0 && scanpos == lastpos) - throw new LookaheadSuccess(); - return false; - } - - /** Get the next Token. */ - final public Token getNextToken() { - if (token.next != null) - token = token.next; - else - token = token.next = tokenSource.getNextToken(); - nextTokenIndex = -1; - genInt++; - return token; - } - - /** Get the specific Token. */ - final public Token getToken(int index) { - Token t = token; - for (int i = 0; i < index; i++) { - if (t.next != null) - t = t.next; - else - t = t.next = tokenSource.getNextToken(); - } - return t; - } - - private int jj_ntk() { - if ((nextToken = token.next) == null) { - return (nextTokenIndex = (token.next = tokenSource.getNextToken()).kind); - } else { - return (nextTokenIndex = nextToken.kind); - } - } - - private final java.util.List expentries = new java.util.ArrayList<>(); - - private int[] expentry; - - private int kind = -1; - - private final int[] lastTokens = new int[100]; - - private int endpos; - - private void jj_add_error_token(int kind, int pos) { - if (pos >= 100) - return; - if (pos == endpos + 1) { - lastTokens[endpos++] = kind; - } else if (endpos != 0) { - expentry = new int[endpos]; - System.arraycopy(lastTokens, 0, expentry, 0, endpos); - entriesLoop: for (int[] jj_expentry1 : expentries) { - if (jj_expentry1.length == expentry.length) { - for (int i = 0; i < expentry.length; i++) { - if (jj_expentry1[i] != expentry[i]) { - continue entriesLoop; - } - } - expentries.add(expentry); - break; - } - } - if (pos != 0) - lastTokens[(endpos = pos) - 1] = kind; - } - } - - /** Generate TokenException. */ - TokenException raiseTokenException() { - expentries.clear(); - boolean[] la1tokens = new boolean[21]; - if (kind >= 0) { - la1tokens[kind] = true; - kind = -1; - } - for (int i = 0; i < 19; i++) { - if (laA[i] == genInt) { - for (int j = 0; j < 32; j++) { - if ((laB[i] & (1 << j)) != 0) { - la1tokens[j] = true; - } - } - } - } - for (int i = 0; i < 21; i++) { - if (la1tokens[i]) { - expentry = new int[1]; - expentry[0] = i; - expentries.add(expentry); - } - } - endpos = 0; - jj_rescan_token(); - jj_add_error_token(0, 0); - int[][] exptokseq = new int[expentries.size()][]; - for (int i = 0; i < expentries.size(); i++) { - exptokseq[i] = expentries.get(i); - } - return new TokenException(token, exptokseq, tokenImage); - } - - /** Enable tracing. */ - final public void enable_tracing() { - } - - /** Disable tracing. */ - final public void disable_tracing() { - } - - private void jj_rescan_token() { - rescan = true; - for (int i = 0; i < 2; i++) { - try { - JJCalls p = rtns[i]; - do { - if (p.gen > genInt) { - laInt = p.arg; - lastpos = scanpos = p.first; - switch (i) { - case 0: - jj_3_1(); - break; - case 1: - jj_3_2(); - break; - } - } - p = p.next; - } while (p != null); - } catch (LookaheadSuccess ls) { - } - } - rescan = false; - } - - private void jj_save(int index, int xla) { - JJCalls p = rtns[index]; - while (p.gen > genInt) { - if (p.next == null) { - p = p.next = new JJCalls(); - break; - } - p = p.next; - } - p.gen = genInt + xla - laInt; - p.first = token; - p.arg = xla; - } - - static final class JJCalls { - - int gen; - - Token first; - - int arg; - - JJCalls next; - - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. LocalUnitFormatParser.java */ +package tec.uom.se.internal.format; + +import static tec.uom.se.internal.format.UnitTokenConstants.*; + +import javax.measure.Unit; + +import tec.uom.se.AbstractUnit; +import tec.uom.se.format.SymbolMap; +import tec.uom.se.function.LogConverter; +import tec.uom.se.unit.MetricPrefix; + +/** + * @deprecated use {@link UnitFormatParser} FIXME there are some details e.g. Exception handling that are different, try to resolve or keep LUFP + */ +@SuppressWarnings({ "rawtypes", "unchecked" }) +public final class LocalUnitFormatParser { + + private static class Exponent { + + public final int pow; + + public final int root; + + public Exponent(int pow, int root) { + this.pow = pow; + this.root = root; + } + } + + private SymbolMap symbols; + + public LocalUnitFormatParser(SymbolMap symbols, java.io.Reader in) { + this(in); + this.symbols = symbols; + } + + final public Unit parseUnit() throws TokenException { + Unit result = CompoundExpr(); + consumeToken(0); + { + return result; + } + } + + final public Unit CompoundExpr() throws TokenException { + throw new UnsupportedOperationException("Compound units not supported"); + } + + final public Unit AddExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Number n1 = null; + Token sign1 = null; + Number n2 = null; + Token sign2 = null; + if (jj_2_1(2147483647)) { + n1 = NumberExpr(); + sign1 = Sign(); + } else { + } + result = MulExpr(); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case PLUS: + case MINUS: + sign2 = Sign(); + n2 = NumberExpr(); + break; + default: + laA[1] = genInt; + } + if (n1 != null) { + if (sign1.image.equals("-")) { + result = result.multiply(-1); + } + result = result.shift(n1.doubleValue()); + } + if (n2 != null) { + double offset = n2.doubleValue(); + if (sign2.image.equals("-")) { + offset = -offset; + } + result = result.shift(offset); + } + { + return result; + } + } + + final public Unit MulExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Unit temp = AbstractUnit.ONE; + result = ExponentExpr(); + label_2: while (true) { + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case ASTERISK: + case MIDDLE_DOT: + case SOLIDUS: + break; + default: + laA[2] = genInt; + break label_2; + } + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case ASTERISK: + case MIDDLE_DOT: + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case ASTERISK: + consumeToken(ASTERISK); + break; + case MIDDLE_DOT: + consumeToken(MIDDLE_DOT); + break; + default: + laA[3] = genInt; + consumeToken(-1); + throw new TokenException(); + } + temp = ExponentExpr(); + result = result.multiply(temp); + break; + case SOLIDUS: + consumeToken(SOLIDUS); + temp = ExponentExpr(); + result = result.divide(temp); + break; + default: + laA[4] = genInt; + consumeToken(-1); + throw new TokenException(); + } + } + { + return result; + } + } + + final public Unit ExponentExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Exponent exponent = null; + Token token = null; + if (jj_2_2(2147483647)) { + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case INTEGER: + token = consumeToken(INTEGER); + break; + case E: + token = consumeToken(E); + break; + default: + laA[5] = genInt; + consumeToken(-1); + throw new TokenException(); + } + consumeToken(CARET); + result = AtomicExpr(); + double base; + if (token.kind == INTEGER) { + base = Integer.parseInt(token.image); + } else { + base = StrictMath.E; + } + { + return result.transform(new LogConverter(base).inverse()); + } + } else { + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case OPEN_PAREN: + case INTEGER: + case FLOATING_POINT: + case UNIT_IDENTIFIER: + result = AtomicExpr(); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case CARET: + case SUPERSCRIPT_INTEGER: + exponent = Exp(); + break; + default: + laA[6] = genInt; + } + if (exponent != null) { + if (exponent.pow != 1) { + result = result.pow(exponent.pow); + } + if (exponent.root != 1) { + result = result.root(exponent.root); + } + } + { + return result; + } + case LOG: + case NAT_LOG: + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case LOG: + consumeToken(LOG); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case INTEGER: + token = consumeToken(INTEGER); + break; + default: + laA[7] = genInt; + } + break; + case NAT_LOG: + token = consumeToken(NAT_LOG); + break; + default: + laA[8] = genInt; + consumeToken(-1); + throw new TokenException(); + } + consumeToken(OPEN_PAREN); + result = AddExpr(); + consumeToken(CLOSE_PAREN); + double base = 10; + if (token != null) { + if (token.kind == INTEGER) { + base = Integer.parseInt(token.image); + } else if (token.kind == NAT_LOG) { + base = StrictMath.E; + } + } + { + return result.transform(new LogConverter(base)); + } + default: + laA[9] = genInt; + consumeToken(-1); + throw new TokenException(); + } + } + } + + final public Unit AtomicExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Number n = null; + Token token = null; + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case INTEGER: + case FLOATING_POINT: + n = NumberExpr(); + if (n instanceof Integer) { + { + return result.multiply(n.intValue()); + } + } else { + { + return result.multiply(n.doubleValue()); + } + } + case UNIT_IDENTIFIER: + token = consumeToken(UNIT_IDENTIFIER); + Unit unit = symbols.getUnit(token.image); + if (unit == null) { + MetricPrefix prefix = symbols.getPrefix(token.image); + if (prefix != null) { + String prefixSymbol = symbols.getSymbol(prefix); + unit = symbols.getUnit(token.image.substring(prefixSymbol.length())); + if (unit != null) { + { + return unit.transform(prefix.getConverter()); + } + } + } + { + throw new TokenException(); + } + } else { + { + return unit; + } + } + case OPEN_PAREN: + consumeToken(OPEN_PAREN); + result = AddExpr(); + consumeToken(CLOSE_PAREN); + { + return result; + } + default: + laA[10] = genInt; + consumeToken(-1); + throw new TokenException(); + } + } + + final public Token Sign() throws TokenException { + Token result = null; + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case PLUS: + result = consumeToken(PLUS); + break; + case MINUS: + result = consumeToken(MINUS); + break; + default: + laA[11] = genInt; + consumeToken(-1); + throw new TokenException(); + } + { + return result; + } + } + + final public Number NumberExpr() throws TokenException { + Token token = null; + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case INTEGER: + token = consumeToken(INTEGER); + { + return Long.valueOf(token.image); + } + case FLOATING_POINT: + token = consumeToken(FLOATING_POINT); + { + return Double.valueOf(token.image); + } + default: + laA[12] = genInt; + consumeToken(-1); + throw new TokenException(); + } + } + + final public Exponent Exp() throws TokenException { + Token powSign = null; + Token powToken = null; + Token rootSign = null; + Token rootToken = null; + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case CARET: + consumeToken(CARET); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case PLUS: + case MINUS: + case INTEGER: + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case PLUS: + case MINUS: + powSign = Sign(); + break; + default: + laA[13] = genInt; + } + powToken = consumeToken(INTEGER); + int pow = Integer.parseInt(powToken.image); + if ((powSign != null) && powSign.image.equals("-")) { + pow = -pow; + } + { + return new Exponent(pow, 1); + } + case OPEN_PAREN: + consumeToken(OPEN_PAREN); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case PLUS: + case MINUS: + powSign = Sign(); + break; + default: + laA[14] = genInt; + } + powToken = consumeToken(INTEGER); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case SOLIDUS: + consumeToken(SOLIDUS); + switch ((nextTokenIndex == -1) ? jj_ntk() : nextTokenIndex) { + case PLUS: + case MINUS: + rootSign = Sign(); + break; + default: + laA[15] = genInt; + } + rootToken = consumeToken(INTEGER); + break; + default: + laA[16] = genInt; + } + consumeToken(CLOSE_PAREN); + pow = Integer.parseInt(powToken.image); + if ((powSign != null) && powSign.image.equals("-")) { + pow = -pow; + } + int root = 1; + if (rootToken != null) { + root = Integer.parseInt(rootToken.image); + if ((rootSign != null) && rootSign.image.equals("-")) { + root = -root; + } + } + { + return new Exponent(pow, root); + } + default: + laA[17] = genInt; + consumeToken(-1); + throw new TokenException(); + } + case SUPERSCRIPT_INTEGER: + powToken = consumeToken(SUPERSCRIPT_INTEGER); + int pow = 0; + for (int i = 0; i < powToken.image.length(); i += 1) { + pow *= 10; + switch (powToken.image.charAt(i)) { + case '\u00b9': + pow += 1; + break; + case '\u00b2': + pow += 2; + break; + case '\u00b3': + pow += 3; + break; + case '\u2074': + pow += 4; + break; + case '\u2075': + pow += 5; + break; + case '\u2076': + pow += 6; + break; + case '\u2077': + pow += 7; + break; + case '\u2078': + pow += 8; + break; + case '\u2079': + pow += 9; + break; + } + } + { + return new Exponent(pow, 1); + } + default: + laA[18] = genInt; + consumeToken(-1); + throw new TokenException(); + } + } + + private boolean jj_2_1(int xla) { + laInt = xla; + lastpos = scanpos = token; + try { + return !jj_3_1(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(0, xla); + } + } + + private boolean jj_2_2(int xla) { + laInt = xla; + lastpos = scanpos = token; + try { + return !jj_3_2(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(1, xla); + } + } + + private boolean jj_3R_3() { + Token xsp; + xsp = scanpos; + if (jj_3R_5()) { + scanpos = xsp; + if (jj_3R_6()) + return true; + } + return false; + } + + private boolean jj_3R_6() { + return scanToken(FLOATING_POINT); + } + + private boolean jj_3_2() { + Token xsp; + xsp = scanpos; + if (scanToken(14)) { + scanpos = xsp; + if (scanToken(19)) + return true; + } + return scanToken(CARET); + } + + private boolean jj_3_1() { + return jj_3R_3() || jj_3R_4(); + } + + private boolean jj_3R_4() { + Token xsp; + xsp = scanpos; + if (scanToken(5)) { + scanpos = xsp; + if (scanToken(6)) + return true; + } + return false; + } + + private boolean jj_3R_5() { + return scanToken(INTEGER); + } + + /** Generated Token Manager. */ + public UnitTokenManager tokenSource; + + DefaultCharStream inputStream; + + /** Current token. */ + public Token token; + + /** Next token. */ + public Token nextToken; + + private int nextTokenIndex; + + private Token scanpos, lastpos; + + private int laInt; + + private int genInt; + + final private int[] laA = new int[19]; + + static private int[] laB; + + static { + init(); + } + + private static void init() { + laB = new int[] { 0x800, 0x60, 0x380, 0x180, 0x380, 0x84000, 0x8400, 0x4000, 0x60000, 0x175000, 0x115000, 0x60, 0x14000, 0x60, 0x60, 0x60, 0x200, + 0x5060, 0x8400, }; + } + + final private JJCalls[] rtns = new JJCalls[2]; + + private boolean rescan = false; + + private int gcInt = 0; + + /** Constructor with InputStream. */ + public LocalUnitFormatParser(java.io.InputStream stream) { + this(stream, null); + } + + /** Constructor with InputStream and supplied encoding */ + public LocalUnitFormatParser(java.io.InputStream stream, String encoding) { + try { + inputStream = new DefaultCharStream(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + tokenSource = new UnitTokenManager(inputStream); + token = new Token(); + nextTokenIndex = -1; + genInt = 0; + for (int i = 0; i < 19; i++) { + laA[i] = -1; + } + for (int i = 0; i < rtns.length; i++) { + rtns[i] = new JJCalls(); + } + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream stream) { + ReInit(stream, null); + } + + /** Reinitialise. */ + public void ReInit(java.io.InputStream stream, String encoding) { + try { + inputStream.ReInit(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + tokenSource.ReInit(inputStream); + token = new Token(); + nextTokenIndex = -1; + genInt = 0; + for (int i = 0; i < 19; i++) { + laA[i] = -1; + } + for (int i = 0; i < rtns.length; i++) { + rtns[i] = new JJCalls(); + } + } + + /** Constructor. */ + public LocalUnitFormatParser(java.io.Reader stream) { + inputStream = new DefaultCharStream(stream, 1, 1); + tokenSource = new UnitTokenManager(inputStream); + token = new Token(); + nextTokenIndex = -1; + genInt = 0; + for (int i = 0; i < 19; i++) { + laA[i] = -1; + } + for (int i = 0; i < rtns.length; i++) { + rtns[i] = new JJCalls(); + } + } + + /** Reinitialise. */ + public void ReInit(java.io.Reader stream) { + inputStream.ReInit(stream, 1, 1); + tokenSource.ReInit(inputStream); + token = new Token(); + nextTokenIndex = -1; + genInt = 0; + for (int i = 0; i < 19; i++) { + laA[i] = -1; + } + for (int i = 0; i < rtns.length; i++) { + rtns[i] = new JJCalls(); + } + } + + /** Constructor with generated Token Manager. */ + public LocalUnitFormatParser(UnitTokenManager tm) { + tokenSource = tm; + token = new Token(); + nextTokenIndex = -1; + genInt = 0; + for (int i = 0; i < 19; i++) { + laA[i] = -1; + } + for (int i = 0; i < rtns.length; i++) { + rtns[i] = new JJCalls(); + } + } + + /** Reinitialise. */ + public void ReInit(UnitTokenManager tm) { + tokenSource = tm; + token = new Token(); + nextTokenIndex = -1; + genInt = 0; + for (int i = 0; i < 19; i++) { + laA[i] = -1; + } + for (int i = 0; i < rtns.length; i++) { + rtns[i] = new JJCalls(); + } + } + + private Token consumeToken(int kind) throws TokenException { + Token oldToken; + if ((oldToken = token).next != null) + token = token.next; + else + token = token.next = tokenSource.getNextToken(); + nextTokenIndex = -1; + if (token.kind == kind) { + genInt++; + if (++gcInt > 100) { + gcInt = 0; + for (JJCalls jj_2_rtn : rtns) { + JJCalls c = jj_2_rtn; + while (c != null) { + if (c.gen < genInt) + c.first = null; + c = c.next; + } + } + } + return token; + } + token = oldToken; + this.kind = kind; + throw raiseTokenException(); + } + + static private final class LookaheadSuccess extends java.lang.RuntimeException { + private static final long serialVersionUID = 2205332054119123041L; + } + + private boolean scanToken(int kind) { + if (scanpos == lastpos) { + laInt--; + if (scanpos.next == null) { + lastpos = scanpos = scanpos.next = tokenSource.getNextToken(); + } else { + lastpos = scanpos = scanpos.next; + } + } else { + scanpos = scanpos.next; + } + if (rescan) { + int i = 0; + Token tok = token; + while (tok != null && tok != scanpos) { + i++; + tok = tok.next; + } + if (tok != null) + jj_add_error_token(kind, i); + } + if (scanpos.kind != kind) + return true; + if (laInt == 0 && scanpos == lastpos) + throw new LookaheadSuccess(); + return false; + } + + /** Get the next Token. */ + final public Token getNextToken() { + if (token.next != null) + token = token.next; + else + token = token.next = tokenSource.getNextToken(); + nextTokenIndex = -1; + genInt++; + return token; + } + + /** Get the specific Token. */ + final public Token getToken(int index) { + Token t = token; + for (int i = 0; i < index; i++) { + if (t.next != null) + t = t.next; + else + t = t.next = tokenSource.getNextToken(); + } + return t; + } + + private int jj_ntk() { + if ((nextToken = token.next) == null) { + return (nextTokenIndex = (token.next = tokenSource.getNextToken()).kind); + } else { + return (nextTokenIndex = nextToken.kind); + } + } + + private final java.util.List expentries = new java.util.ArrayList<>(); + + private int[] expentry; + + private int kind = -1; + + private final int[] lastTokens = new int[100]; + + private int endpos; + + private void jj_add_error_token(int kind, int pos) { + if (pos >= 100) + return; + if (pos == endpos + 1) { + lastTokens[endpos++] = kind; + } else if (endpos != 0) { + expentry = new int[endpos]; + System.arraycopy(lastTokens, 0, expentry, 0, endpos); + entriesLoop: for (int[] jj_expentry1 : expentries) { + if (jj_expentry1.length == expentry.length) { + for (int i = 0; i < expentry.length; i++) { + if (jj_expentry1[i] != expentry[i]) { + continue entriesLoop; + } + } + expentries.add(expentry); + break; + } + } + if (pos != 0) + lastTokens[(endpos = pos) - 1] = kind; + } + } + + /** Generate TokenException. */ + TokenException raiseTokenException() { + expentries.clear(); + boolean[] la1tokens = new boolean[21]; + if (kind >= 0) { + la1tokens[kind] = true; + kind = -1; + } + for (int i = 0; i < 19; i++) { + if (laA[i] == genInt) { + for (int j = 0; j < 32; j++) { + if ((laB[i] & (1 << j)) != 0) { + la1tokens[j] = true; + } + } + } + } + for (int i = 0; i < 21; i++) { + if (la1tokens[i]) { + expentry = new int[1]; + expentry[0] = i; + expentries.add(expentry); + } + } + endpos = 0; + jj_rescan_token(); + jj_add_error_token(0, 0); + int[][] exptokseq = new int[expentries.size()][]; + for (int i = 0; i < expentries.size(); i++) { + exptokseq[i] = expentries.get(i); + } + return new TokenException(token, exptokseq, tokenImage); + } + + /** Enable tracing. */ + final public void enable_tracing() { + } + + /** Disable tracing. */ + final public void disable_tracing() { + } + + private void jj_rescan_token() { + rescan = true; + for (int i = 0; i < 2; i++) { + try { + JJCalls p = rtns[i]; + do { + if (p.gen > genInt) { + laInt = p.arg; + lastpos = scanpos = p.first; + switch (i) { + case 0: + jj_3_1(); + break; + case 1: + jj_3_2(); + break; + } + } + p = p.next; + } while (p != null); + } catch (LookaheadSuccess ls) { + } + } + rescan = false; + } + + private void jj_save(int index, int xla) { + JJCalls p = rtns[index]; + while (p.gen > genInt) { + if (p.next == null) { + p = p.next = new JJCalls(); + break; + } + p = p.next; + } + p.gen = genInt + xla - laInt; + p.first = token; + p.arg = xla; + } + + static final class JJCalls { + + int gen; + + Token first; + + int arg; + + JJCalls next; + + } +} diff --git a/src/main/java/tec/uom/se/internal/format/Token.java b/src/main/java/tec/uom/se/internal/format/Token.java index 132ab07d..7a8f288a 100644 --- a/src/main/java/tec/uom/se/internal/format/Token.java +++ b/src/main/java/tec/uom/se/internal/format/Token.java @@ -1,144 +1,144 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */ -/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ -package tec.uom.se.internal.format; - -/** - * Describes the input token stream. - * - * @version 5.2, April 16, 2014 - */ - -public final class Token { - - /** - * The Serialization identifier for this class. Increment only if the serialized form of the class changes. - */ - // private static final long serialVersionUID = 2188279658897600591L; - - /** - * An integer that describes the kind of this token. This numbering system is determined by JavaCCParser, and a table of these numbers is stored in - * the file ...Constants.java. - */ - public int kind; - - /** The line number of the first character of this Token. */ - public int beginLine; - /** The column number of the first character of this Token. */ - public int beginColumn; - /** The line number of the last character of this Token. */ - public int endLine; - /** The column number of the last character of this Token. */ - public int endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input stream. If this is the last token from the input stream, or if the token - * manager has not read tokens beyond this one, this field is set to null. This is true only if this token is also a regular token. Otherwise, see - * below for a description of the contents of this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this token, but after the immediately preceding regular (non-special) token. If - * there are no such special tokens, this field is set to null. When there are more than one such special token, this field refers to the last of - * these special tokens, which in turn refers to the next previous special token through its specialToken field, and so on until the first special - * token (whose specialToken field is null). The next fields of special tokens refer to other special tokens that immediately follow it (without an - * intervening regular token). If there is no such token, this field is null. - */ - public Token specialToken; - - /** - * An optional attribute value of the Token. Tokens which are not used as syntactic sugar will often contain meaningful values that will be used - * later on by the compiler or interpreter. This attribute value is often different from the image. Any subclass of Token that actually wants to - * return a non-null value can override this method as appropriate. - */ - public Object getValue() { - return null; - } - - /** - * No-argument constructor - */ - public Token() { - } - - /** - * Constructs a new token for the specified Image. - */ - public Token(int kind) { - this(kind, null); - } - - /** - * Constructs a new token for the specified Image and Kind. - */ - public Token(int kind, String image) { - this.kind = kind; - this.image = image; - } - - /** - * Returns the image. - */ - public String toString() { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you can create and return subclass objects based on the value of ofKind. Simply add - * the cases to the switch for all those special cases. For example, if you have a subclass of Token called IDToken that you want to create if - * ofKind is ID, simply add something like : - * - * case MyParserConstants.ID : return new IDToken(ofKind, image); - * - * to the following switch statement. Then you can cast matchedToken variable to the appropriate type and use sit in your lexical actions. - */ - public static Token newToken(int ofKind, String image) { - switch (ofKind) { - default: - return new Token(ofKind, image); - } - } - - public static Token newToken(int ofKind) { - return newToken(ofKind, null); - } - -} -/* - * JavaCC - OriginalChecksum=08d08345e10cca30522247698d4478e6 (do not edit this - * line) - */ +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */ +/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ +package tec.uom.se.internal.format; + +/** + * Describes the input token stream. + * + * @version 5.2, April 16, 2014 + */ + +public final class Token { + + /** + * The Serialization identifier for this class. Increment only if the serialized form of the class changes. + */ + // private static final long serialVersionUID = 2188279658897600591L; + + /** + * An integer that describes the kind of this token. This numbering system is determined by JavaCCParser, and a table of these numbers is stored in + * the file ...Constants.java. + */ + public int kind; + + /** The line number of the first character of this Token. */ + public int beginLine; + /** The column number of the first character of this Token. */ + public int beginColumn; + /** The line number of the last character of this Token. */ + public int endLine; + /** The column number of the last character of this Token. */ + public int endColumn; + + /** + * The string image of the token. + */ + public String image; + + /** + * A reference to the next regular (non-special) token from the input stream. If this is the last token from the input stream, or if the token + * manager has not read tokens beyond this one, this field is set to null. This is true only if this token is also a regular token. Otherwise, see + * below for a description of the contents of this field. + */ + public Token next; + + /** + * This field is used to access special tokens that occur prior to this token, but after the immediately preceding regular (non-special) token. If + * there are no such special tokens, this field is set to null. When there are more than one such special token, this field refers to the last of + * these special tokens, which in turn refers to the next previous special token through its specialToken field, and so on until the first special + * token (whose specialToken field is null). The next fields of special tokens refer to other special tokens that immediately follow it (without an + * intervening regular token). If there is no such token, this field is null. + */ + public Token specialToken; + + /** + * An optional attribute value of the Token. Tokens which are not used as syntactic sugar will often contain meaningful values that will be used + * later on by the compiler or interpreter. This attribute value is often different from the image. Any subclass of Token that actually wants to + * return a non-null value can override this method as appropriate. + */ + public Object getValue() { + return null; + } + + /** + * No-argument constructor + */ + public Token() { + } + + /** + * Constructs a new token for the specified Image. + */ + public Token(int kind) { + this(kind, null); + } + + /** + * Constructs a new token for the specified Image and Kind. + */ + public Token(int kind, String image) { + this.kind = kind; + this.image = image; + } + + /** + * Returns the image. + */ + public String toString() { + return image; + } + + /** + * Returns a new Token object, by default. However, if you want, you can create and return subclass objects based on the value of ofKind. Simply add + * the cases to the switch for all those special cases. For example, if you have a subclass of Token called IDToken that you want to create if + * ofKind is ID, simply add something like : + * + * case MyParserConstants.ID : return new IDToken(ofKind, image); + * + * to the following switch statement. Then you can cast matchedToken variable to the appropriate type and use sit in your lexical actions. + */ + public static Token newToken(int ofKind, String image) { + switch (ofKind) { + default: + return new Token(ofKind, image); + } + } + + public static Token newToken(int ofKind) { + return newToken(ofKind, null); + } + +} +/* + * JavaCC - OriginalChecksum=08d08345e10cca30522247698d4478e6 (do not edit this + * line) + */ diff --git a/src/main/java/tec/uom/se/internal/format/TokenException.java b/src/main/java/tec/uom/se/internal/format/TokenException.java index 4f58f3ca..b10be095 100644 --- a/src/main/java/tec/uom/se/internal/format/TokenException.java +++ b/src/main/java/tec/uom/se/internal/format/TokenException.java @@ -1,198 +1,198 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. TokenException.java Version 5.0 */ -/* JavaCCOptions:KEEP_LINE_COL=null */ -package tec.uom.se.internal.format; - -import javax.measure.MeasurementException; - -/** - * This exception is thrown when token errors are encountered. You can explicitly create objects of this exception type by calling the method - * raiseTokenException in the generated parser. - * - * You can modify this class to customize your error reporting mechanisms so long as you retain the public fields. - * - * @author Jean-Marie Dautelle - * @author Werner Keil - * @version 0.5.4, Jan 20, 2015 - */ -public class TokenException extends MeasurementException { - // TODO try to merge this with ParserException - /** - * The Serialization identifier for this class. Increment only if the serialized form of the class changes. - */ - private static final long serialVersionUID = 2932151235799168061L; - - /** - * This constructor is used by the method "raiseTokenException" in the generated parser. Calling this constructor generates a new object of this - * type with the fields "currentToken", "expectedTokenSequences", and "tokenImage" set. - */ - public TokenException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal) { - super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal)); - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever purpose you can think of. Constructing the exception in this manner makes the - * exception behave in the normal way - i.e., as documented in the class "Throwable". The fields "errorToken", "expectedTokenSequences", and - * "tokenImage" do not contain relevant information. The JavaCC generated code does not use these constructors. - */ - - public TokenException() { - super(); - } - - /** Constructor with message. */ - public TokenException(String message) { - super(message); - } - - /** - * This is the last token that has been consumed successfully. If this object has been created due to a parse error, the token followng this token - * will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array of integers represents a sequence of tokens (by their ordinal values) that is - * expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated parser within which the parse error occurred. This array is defined in the - * generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * It uses "currentToken" and "expectedTokenSequences" to generate a parse error message and returns it. If this object has been created due to a - * parse error, and you do not catch it (it gets thrown from the parser) the correct error message gets displayed. - */ - private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) { - String eol = System.getProperty("line.separator", "\n"); - StringBuilder expected = new StringBuilder(); - int maxSize = 0; - for (int[] expectedTokenSequence : expectedTokenSequences) { - if (maxSize < expectedTokenSequence.length) { - maxSize = expectedTokenSequence.length; - } - for (int anExpectedTokenSequence : expectedTokenSequence) { - expected.append(tokenImage[anExpectedTokenSequence]).append(' '); - } - if (expectedTokenSequence[expectedTokenSequence.length - 1] != 0) { - expected.append("..."); - } - expected.append(eol).append(" "); - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) - retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += " " + tokenImage[tok.kind]; - retval += " \""; - retval += add_escapes(tok.image); - retval += " \""; - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected.toString(); - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version when these raw version cannot be used as part of an ASCII string literal. - */ - static String add_escapes(String str) { - StringBuilder retval = new StringBuilder(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) { - case 0: - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u").append(s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - } - } - return retval.toString(); - } - -} -/* - * JavaCC - OriginalChecksum=c67b0f8ee6c642900399352b33f90efd (do not edit this - * line) - */ +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. TokenException.java Version 5.0 */ +/* JavaCCOptions:KEEP_LINE_COL=null */ +package tec.uom.se.internal.format; + +import javax.measure.MeasurementException; + +/** + * This exception is thrown when token errors are encountered. You can explicitly create objects of this exception type by calling the method + * raiseTokenException in the generated parser. + * + * You can modify this class to customize your error reporting mechanisms so long as you retain the public fields. + * + * @author Jean-Marie Dautelle + * @author Werner Keil + * @version 0.5.4, Jan 20, 2015 + */ +public class TokenException extends MeasurementException { + // TODO try to merge this with ParserException + /** + * The Serialization identifier for this class. Increment only if the serialized form of the class changes. + */ + private static final long serialVersionUID = 2932151235799168061L; + + /** + * This constructor is used by the method "raiseTokenException" in the generated parser. Calling this constructor generates a new object of this + * type with the fields "currentToken", "expectedTokenSequences", and "tokenImage" set. + */ + public TokenException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal) { + super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal)); + currentToken = currentTokenVal; + expectedTokenSequences = expectedTokenSequencesVal; + tokenImage = tokenImageVal; + } + + /** + * The following constructors are for use by you for whatever purpose you can think of. Constructing the exception in this manner makes the + * exception behave in the normal way - i.e., as documented in the class "Throwable". The fields "errorToken", "expectedTokenSequences", and + * "tokenImage" do not contain relevant information. The JavaCC generated code does not use these constructors. + */ + + public TokenException() { + super(); + } + + /** Constructor with message. */ + public TokenException(String message) { + super(message); + } + + /** + * This is the last token that has been consumed successfully. If this object has been created due to a parse error, the token followng this token + * will (therefore) be the first error token. + */ + public Token currentToken; + + /** + * Each entry in this array is an array of integers. Each array of integers represents a sequence of tokens (by their ordinal values) that is + * expected at this point of the parse. + */ + public int[][] expectedTokenSequences; + + /** + * This is a reference to the "tokenImage" array of the generated parser within which the parse error occurred. This array is defined in the + * generated ...Constants interface. + */ + public String[] tokenImage; + + /** + * It uses "currentToken" and "expectedTokenSequences" to generate a parse error message and returns it. If this object has been created due to a + * parse error, and you do not catch it (it gets thrown from the parser) the correct error message gets displayed. + */ + private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) { + String eol = System.getProperty("line.separator", "\n"); + StringBuilder expected = new StringBuilder(); + int maxSize = 0; + for (int[] expectedTokenSequence : expectedTokenSequences) { + if (maxSize < expectedTokenSequence.length) { + maxSize = expectedTokenSequence.length; + } + for (int anExpectedTokenSequence : expectedTokenSequence) { + expected.append(tokenImage[anExpectedTokenSequence]).append(' '); + } + if (expectedTokenSequence[expectedTokenSequence.length - 1] != 0) { + expected.append("..."); + } + expected.append(eol).append(" "); + } + String retval = "Encountered \""; + Token tok = currentToken.next; + for (int i = 0; i < maxSize; i++) { + if (i != 0) + retval += " "; + if (tok.kind == 0) { + retval += tokenImage[0]; + break; + } + retval += " " + tokenImage[tok.kind]; + retval += " \""; + retval += add_escapes(tok.image); + retval += " \""; + tok = tok.next; + } + retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; + retval += "." + eol; + if (expectedTokenSequences.length == 1) { + retval += "Was expecting:" + eol + " "; + } else { + retval += "Was expecting one of:" + eol + " "; + } + retval += expected.toString(); + return retval; + } + + /** + * The end of line string for this machine. + */ + protected String eol = System.getProperty("line.separator", "\n"); + + /** + * Used to convert raw characters to their escaped version when these raw version cannot be used as part of an ASCII string literal. + */ + static String add_escapes(String str) { + StringBuilder retval = new StringBuilder(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) { + case 0: + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u").append(s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + } + } + return retval.toString(); + } + +} +/* + * JavaCC - OriginalChecksum=c67b0f8ee6c642900399352b33f90efd (do not edit this + * line) + */ diff --git a/src/main/java/tec/uom/se/internal/format/TokenMgrError.java b/src/main/java/tec/uom/se/internal/format/TokenMgrError.java index 7e8c6095..d7be862b 100644 --- a/src/main/java/tec/uom/se/internal/format/TokenMgrError.java +++ b/src/main/java/tec/uom/se/internal/format/TokenMgrError.java @@ -1,163 +1,163 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */ -/* JavaCCOptions: */ -package tec.uom.se.internal.format; - -/** Token Manager Error. */ -public class TokenMgrError extends Error { - - /** - * The Serialization identifier for this class. Increment only if the serialized form of the class changes. - */ - private static final long serialVersionUID = -3348968864772188432L; - - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occurred. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt was made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their escaped (or unicode escaped) equivalents in the given string - */ - protected static String addEscapes(String str) { - StringBuilder retval = new StringBuilder(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) { - case 0: - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u").append(s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the token manager to indicate a lexical error. Parameters : EOFSeen : indicates if - * EOF caused the lexical error curLexState : lexical state in which this error occurred errorLine : line number when the error occurred errorColumn - * : column number when the error occurred errorAfter : prefix that was seen before this error occurred curchar : the offending character Note: You - * can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int errorLine, int errorColumn, String errorAfter, char curChar) { - return ("Lexical error at line " + errorLine + ", column " + errorColumn + ". Encountered: " - + (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int) curChar + "), ") + "after : \"" - + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are - * not of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - /** No arg constructor. */ - public TokenMgrError() { - } - - /** Constructor with message and reason. */ - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - /** Full Constructor. */ - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, errorLine, errorColumn, errorAfter, curChar), reason); - } -} -/* - * JavaCC - OriginalChecksum=8a6e5be586cca28053ad55584e013006 (do not edit this - * line) - */ +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */ +/* JavaCCOptions: */ +package tec.uom.se.internal.format; + +/** Token Manager Error. */ +public class TokenMgrError extends Error { + + /** + * The Serialization identifier for this class. Increment only if the serialized form of the class changes. + */ + private static final long serialVersionUID = -3348968864772188432L; + + /* + * Ordinals for various reasons why an Error of this type can be thrown. + */ + + /** + * Lexical error occurred. + */ + static final int LEXICAL_ERROR = 0; + + /** + * An attempt was made to create a second instance of a static token manager. + */ + static final int STATIC_LEXER_ERROR = 1; + + /** + * Tried to change to an invalid lexical state. + */ + static final int INVALID_LEXICAL_STATE = 2; + + /** + * Detected (and bailed out of) an infinite loop in the token manager. + */ + static final int LOOP_DETECTED = 3; + + /** + * Indicates the reason why the exception is thrown. It will have one of the above 4 values. + */ + int errorCode; + + /** + * Replaces unprintable characters by their escaped (or unicode escaped) equivalents in the given string + */ + protected static String addEscapes(String str) { + StringBuilder retval = new StringBuilder(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) { + case 0: + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u").append(s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + } + } + return retval.toString(); + } + + /** + * Returns a detailed message for the Error when it is thrown by the token manager to indicate a lexical error. Parameters : EOFSeen : indicates if + * EOF caused the lexical error curLexState : lexical state in which this error occurred errorLine : line number when the error occurred errorColumn + * : column number when the error occurred errorAfter : prefix that was seen before this error occurred curchar : the offending character Note: You + * can customize the lexical error message by modifying this method. + */ + protected static String LexicalError(boolean EOFSeen, int errorLine, int errorColumn, String errorAfter, char curChar) { + return ("Lexical error at line " + errorLine + ", column " + errorColumn + ". Encountered: " + + (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int) curChar + "), ") + "after : \"" + + addEscapes(errorAfter) + "\""); + } + + /** + * You can also modify the body of this method to customize your error messages. For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are + * not of end-users concern, so you can return something like : + * + * "Internal Error : Please file a bug report .... " + * + * from this method for such cases in the release version of your parser. + */ + public String getMessage() { + return super.getMessage(); + } + + /* + * Constructors of various flavors follow. + */ + + /** No arg constructor. */ + public TokenMgrError() { + } + + /** Constructor with message and reason. */ + public TokenMgrError(String message, int reason) { + super(message); + errorCode = reason; + } + + /** Full Constructor. */ + public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { + this(LexicalError(EOFSeen, errorLine, errorColumn, errorAfter, curChar), reason); + } +} +/* + * JavaCC - OriginalChecksum=8a6e5be586cca28053ad55584e013006 (do not edit this + * line) + */ diff --git a/src/main/java/tec/uom/se/internal/format/UnitFormatParser.java b/src/main/java/tec/uom/se/internal/format/UnitFormatParser.java index 24d7bdfd..ef5f23ff 100644 --- a/src/main/java/tec/uom/se/internal/format/UnitFormatParser.java +++ b/src/main/java/tec/uom/se/internal/format/UnitFormatParser.java @@ -1,902 +1,902 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.internal.format; - -import javax.measure.Unit; - -import tec.uom.se.AbstractUnit; -import tec.uom.se.format.SymbolMap; -import tec.uom.se.function.LogConverter; -import tec.uom.se.unit.MetricPrefix; - -/** */ -public final class UnitFormatParser implements UnitTokenConstants { - - private static class Exponent { - final int pow; - final int root; - - public Exponent(int pow, int root) { - this.pow = pow; - this.root = root; - } - } - - private SymbolMap symbols; - - public UnitFormatParser(SymbolMap symbols, java.io.Reader in) { // TODO visiblity - this(in); - this.symbols = symbols; - } - - // - // Parser productions - // - @SuppressWarnings("unused") - public Unit parseUnit() throws TokenException { // TODO visibility - Unit result; - result = compoundExpr(); - jj_consume_token(0); - { - if (true) - return result; - } - throw new Error("Missing return statement in function"); - } - - @SuppressWarnings("unused") - Unit compoundExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - result = addExpr(); - label_1: while (true) { - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case COLON: - break; - default: - jj_la1[0] = jj_gen; - break label_1; - } - jj_consume_token(COLON); - } - { - if (true) - return result; - } - throw new Error("Missing return statement in function"); - } - - @SuppressWarnings("unused") - Unit addExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Number n1 = null; - Token sign1 = null; - Number n2 = null; - Token sign2 = null; - if (jj_2_1(2147483647)) { - n1 = numberExpr(); - sign1 = sign(); - } else { - } - result = mulExpr(); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case PLUS: - case MINUS: - sign2 = sign(); - n2 = numberExpr(); - break; - default: - jj_la1[1] = jj_gen; - } - if (n1 != null) { - if (sign1.image.equals("-")) { - result = result.multiply(-1); - } - result = result.shift(n1.doubleValue()); - } - if (n2 != null) { - double offset = n2.doubleValue(); - if (sign2.image.equals("-")) { - offset = -offset; - } - result = result.shift(offset); - } - { - if (true) - return result; - } - throw new Error("Missing return statement in function"); - } - - Unit mulExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Unit temp = AbstractUnit.ONE; - result = exponentExpr(); - label_2: while (true) { - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case ASTERISK: - case MIDDLE_DOT: - case SOLIDUS: - break; - default: - jj_la1[2] = jj_gen; - break label_2; - } - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case ASTERISK: - case MIDDLE_DOT: - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case ASTERISK: - jj_consume_token(ASTERISK); - break; - case MIDDLE_DOT: - jj_consume_token(MIDDLE_DOT); - break; - default: - jj_la1[3] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - temp = exponentExpr(); - result = result.multiply(temp); - break; - case SOLIDUS: - jj_consume_token(SOLIDUS); - temp = exponentExpr(); - result = result.divide(temp); - break; - default: - jj_la1[4] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - } - // {if (true) - return result;// } - // throw new Error("Missing return statement in function"); - } - - @SuppressWarnings("unused") - Unit exponentExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - Exponent exponent = null; - Token token = null; - if (jj_2_2(2147483647)) { - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case INTEGER: - token = jj_consume_token(INTEGER); - break; - case E: - token = jj_consume_token(E); - break; - default: - jj_la1[5] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - jj_consume_token(CARET); - result = atomicExpr(); - double base; - if (token.kind == INTEGER) { - base = Integer.parseInt(token.image); - } else { - base = E; - } - { - if (true) - return result.transform(new LogConverter(base).inverse()); - } - } else { - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case OPEN_PAREN: - case INTEGER: - case FLOATING_POINT: - case UNIT_IDENTIFIER: - result = atomicExpr(); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case CARET: - case SUPERSCRIPT_INTEGER: - exponent = exp(); - break; - default: - jj_la1[6] = jj_gen; - } - if (exponent != null) { - if (exponent.pow != 1) { - result = result.pow(exponent.pow); - } - if (exponent.root != 1) { - result = result.root(exponent.root); - } - } - { - if (true) - return result; - } - // break; - case LOG: - case NAT_LOG: - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case LOG: - jj_consume_token(LOG); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case INTEGER: - token = jj_consume_token(INTEGER); - break; - default: - jj_la1[7] = jj_gen; - } - break; - case NAT_LOG: - token = jj_consume_token(NAT_LOG); - break; - default: - jj_la1[8] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - jj_consume_token(OPEN_PAREN); - result = addExpr(); - jj_consume_token(CLOSE_PAREN); - double base = 10; - if (token != null) { - if (token.kind == INTEGER) { - base = Integer.parseInt(token.image); - } else if (token.kind == NAT_LOG) { - base = E; - } - } - { - if (true) - return result.transform(new LogConverter(base)); - } - default: - jj_la1[9] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - } - throw new Error("Missing return statement in function"); - } - - Unit atomicExpr() throws TokenException { - Unit result = AbstractUnit.ONE; - // Unit temp = AbstractUnit.ONE; - Number n = null; - Token token = null; - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case INTEGER: - case FLOATING_POINT: - n = numberExpr(); - if (n instanceof Integer) { - { - if (true) - return result.multiply(n.intValue()); - } - } else { - { - if (true) - return result.multiply(n.doubleValue()); - } - } - // break; - case UNIT_IDENTIFIER: - token = jj_consume_token(UNIT_IDENTIFIER); - Unit unit = symbols.getUnit(token.image); - if (unit == null) { - MetricPrefix prefix = symbols.getPrefix(token.image); - if (prefix != null) { - String prefixSymbol = symbols.getSymbol(prefix); - unit = symbols.getUnit(token.image.substring(prefixSymbol.length())); - if (unit != null) { - { - if (true) - return unit.transform(prefix.getConverter()); - } - } - } - { - if (true) - throw new TokenException(); - } - } else { - { - if (true) - return unit; - } - } - // break; - case OPEN_PAREN: - jj_consume_token(OPEN_PAREN); - result = addExpr(); - jj_consume_token(CLOSE_PAREN); - { - if (true) - return result; - } - // break; - default: - jj_la1[10] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - // throw new Error("Missing return statement in function"); - } - - @SuppressWarnings("unused") - Token sign() throws TokenException { - Token result = null; - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case PLUS: - result = jj_consume_token(PLUS); - break; - case MINUS: - result = jj_consume_token(MINUS); - break; - default: - jj_la1[11] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - { - if (true) - return result; - } - throw new Error("Missing return statement in function"); - } - - Number numberExpr() throws TokenException { - Token token = null; - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case INTEGER: - token = jj_consume_token(INTEGER); - { - if (true) - return Long.valueOf(token.image); - } - // break; - case FLOATING_POINT: - token = jj_consume_token(FLOATING_POINT); - { - if (true) - return Double.valueOf(token.image); - } - // break; - default: - jj_la1[12] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - // throw new Error("Missing return statement in function"); - } - - Exponent exp() throws TokenException { - Token powSign = null; - Token powToken = null; - Token rootSign = null; - Token rootToken = null; - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case CARET: - jj_consume_token(CARET); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case PLUS: - case MINUS: - case INTEGER: - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case PLUS: - case MINUS: - powSign = sign(); - break; - default: - jj_la1[13] = jj_gen; - } - powToken = jj_consume_token(INTEGER); - int pow = Integer.parseInt(powToken.image); - if ((powSign != null) && powSign.image.equals("-")) { - pow = -pow; - } - { - if (true) - return new Exponent(pow, 1); - } - case OPEN_PAREN: - jj_consume_token(OPEN_PAREN); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case PLUS: - case MINUS: - powSign = sign(); - break; - default: - jj_la1[14] = jj_gen; - } - powToken = jj_consume_token(INTEGER); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case SOLIDUS: - jj_consume_token(SOLIDUS); - switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { - case PLUS: - case MINUS: - rootSign = sign(); - break; - default: - jj_la1[15] = jj_gen; - } - rootToken = jj_consume_token(INTEGER); - break; - default: - jj_la1[16] = jj_gen; - } - jj_consume_token(CLOSE_PAREN); - pow = Integer.parseInt(powToken.image); - if ((powSign != null) && powSign.image.equals("-")) { - pow = -pow; - } - int root = 1; - if (rootToken != null) { - root = Integer.parseInt(rootToken.image); - if ((rootSign != null) && rootSign.image.equals("-")) { - root = -root; - } - } - { - if (true) - return new Exponent(pow, root); - } - default: - jj_la1[17] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - case SUPERSCRIPT_INTEGER: - powToken = jj_consume_token(SUPERSCRIPT_INTEGER); - int pow = 0; - for (int i = 0; i < powToken.image.length(); i += 1) { - pow *= 10; - switch (powToken.image.charAt(i)) { - case '\u00b9': - pow += 1; - break; - case '\u00b2': - pow += 2; - break; - case '\u00b3': - pow += 3; - break; - case '\u2074': - pow += 4; - break; - case '\u2075': - pow += 5; - break; - case '\u2076': - pow += 6; - break; - case '\u2077': - pow += 7; - break; - case '\u2078': - pow += 8; - break; - case '\u2079': - pow += 9; - break; - } - } - { - if (true) - return new Exponent(pow, 1); - } - // break; - default: - jj_la1[18] = jj_gen; - jj_consume_token(-1); - throw new TokenException(); - } - // throw new Error("Missing return statement in function"); - } - - private boolean jj_2_1(int xla) { - jj_la = xla; - jj_lastpos = jj_scanpos = token; - try { - return !jj_3_1(); - } catch (LookaheadSuccess ls) { - return true; - } finally { - jj_save(0, xla); - } - } - - private boolean jj_2_2(int xla) { - jj_la = xla; - jj_lastpos = jj_scanpos = token; - try { - return !jj_3_2(); - } catch (LookaheadSuccess ls) { - return true; - } finally { - jj_save(1, xla); - } - } - - private boolean jj_3R_3() { - Token xsp; - xsp = jj_scanpos; - if (jj_3R_5()) { - jj_scanpos = xsp; - if (jj_3R_6()) - return true; - } - return false; - } - - private boolean jj_3R_6() { - return jj_scan_token(FLOATING_POINT); - } - - private boolean jj_3_2() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(14)) { - jj_scanpos = xsp; - if (jj_scan_token(19)) - return true; - } - return jj_scan_token(CARET); - } - - private boolean jj_3_1() { - return jj_3R_3() || jj_3R_4(); - } - - private boolean jj_3R_4() { - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(5)) { - jj_scanpos = xsp; - if (jj_scan_token(6)) - return true; - } - return false; - } - - private boolean jj_3R_5() { - return jj_scan_token(INTEGER); - } - - /** Generated Token Manager. */ - private UnitTokenManager token_source; - private DefaultCharStream jj_input_stream; - /** Current token. */ - private Token token; - /** Next token. */ - private Token jj_nt; - private int jj_ntk; - private Token jj_scanpos, jj_lastpos; - private int jj_la; - private int jj_gen; - final private int[] jj_la1 = new int[19]; - static private int[] jj_la1_0; - static { - jj_la1_init_0(); - } - - private static void jj_la1_init_0() { - jj_la1_0 = new int[] { 0x800, 0x60, 0x380, 0x180, 0x380, 0x84000, 0x8400, 0x4000, 0x60000, 0x175000, 0x115000, 0x60, 0x14000, 0x60, 0x60, 0x60, - 0x200, 0x5060, 0x8400, }; - } - - final private JJCalls[] jj_2_rtns = new JJCalls[2]; - private boolean jj_rescan = false; - private int jj_gc = 0; - - /** Constructor with InputStream. */ - UnitFormatParser(java.io.InputStream stream) { - this(stream, null); - } - - /** Constructor with InputStream and supplied encoding */ - UnitFormatParser(java.io.InputStream stream, String encoding) { - try { - jj_input_stream = new DefaultCharStream(stream, encoding, 1, 1); - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - token_source = new UnitTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 19; i++) - jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) - jj_2_rtns[i] = new JJCalls(); - } - - /** Constructor. */ - UnitFormatParser(java.io.Reader stream) { - jj_input_stream = new DefaultCharStream(stream, 1, 1); - token_source = new UnitTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 19; i++) - jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) - jj_2_rtns[i] = new JJCalls(); - } - - /** Reinitialise. */ - // private void reInit(java.io.Reader stream) { - // jj_input_stream.reInit(stream, 1, 1); - // token_source.reInit(jj_input_stream); - // token = new Token(); - // jj_ntk = -1; - // jj_gen = 0; - // for (int i = 0; i < 19; i++) jj_la1[i] = -1; - // for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - // } - - /** Constructor with generated Token Manager. */ - UnitFormatParser(UnitTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 19; i++) - jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) - jj_2_rtns[i] = new JJCalls(); - } - - /** Reinitialise. */ - // private void reInit(UnitTokenManager tm) { - // token_source = tm; - // token = new Token(); - // jj_ntk = -1; - // jj_gen = 0; - // for (int i = 0; i < 19; i++) jj_la1[i] = -1; - // for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - // } - - private Token jj_consume_token(int kind) throws TokenException { - Token oldToken; - if ((oldToken = token).next != null) - token = token.next; - else - token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - if (++jj_gc > 100) { - jj_gc = 0; - for (int i = 0; i < jj_2_rtns.length; i++) { - JJCalls c = jj_2_rtns[i]; - while (c != null) { - if (c.gen < jj_gen) - c.first = null; - c = c.next; - } - } - } - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - static private final class LookaheadSuccess extends java.lang.Error { - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.internal.format; + +import javax.measure.Unit; + +import tec.uom.se.AbstractUnit; +import tec.uom.se.format.SymbolMap; +import tec.uom.se.function.LogConverter; +import tec.uom.se.unit.MetricPrefix; + +/** */ +public final class UnitFormatParser implements UnitTokenConstants { + + private static class Exponent { + final int pow; + final int root; + + public Exponent(int pow, int root) { + this.pow = pow; + this.root = root; + } + } + + private SymbolMap symbols; + + public UnitFormatParser(SymbolMap symbols, java.io.Reader in) { // TODO visiblity + this(in); + this.symbols = symbols; + } + + // + // Parser productions + // + @SuppressWarnings("unused") + public Unit parseUnit() throws TokenException { // TODO visibility + Unit result; + result = compoundExpr(); + jj_consume_token(0); + { + if (true) + return result; + } + throw new Error("Missing return statement in function"); + } + + @SuppressWarnings("unused") + Unit compoundExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + result = addExpr(); + label_1: while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case COLON: + break; + default: + jj_la1[0] = jj_gen; + break label_1; + } + jj_consume_token(COLON); + } + { + if (true) + return result; + } + throw new Error("Missing return statement in function"); + } + + @SuppressWarnings("unused") + Unit addExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Number n1 = null; + Token sign1 = null; + Number n2 = null; + Token sign2 = null; + if (jj_2_1(2147483647)) { + n1 = numberExpr(); + sign1 = sign(); + } else { + } + result = mulExpr(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + sign2 = sign(); + n2 = numberExpr(); + break; + default: + jj_la1[1] = jj_gen; + } + if (n1 != null) { + if (sign1.image.equals("-")) { + result = result.multiply(-1); + } + result = result.shift(n1.doubleValue()); + } + if (n2 != null) { + double offset = n2.doubleValue(); + if (sign2.image.equals("-")) { + offset = -offset; + } + result = result.shift(offset); + } + { + if (true) + return result; + } + throw new Error("Missing return statement in function"); + } + + Unit mulExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Unit temp = AbstractUnit.ONE; + result = exponentExpr(); + label_2: while (true) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASTERISK: + case MIDDLE_DOT: + case SOLIDUS: + break; + default: + jj_la1[2] = jj_gen; + break label_2; + } + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASTERISK: + case MIDDLE_DOT: + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case ASTERISK: + jj_consume_token(ASTERISK); + break; + case MIDDLE_DOT: + jj_consume_token(MIDDLE_DOT); + break; + default: + jj_la1[3] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + temp = exponentExpr(); + result = result.multiply(temp); + break; + case SOLIDUS: + jj_consume_token(SOLIDUS); + temp = exponentExpr(); + result = result.divide(temp); + break; + default: + jj_la1[4] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + } + // {if (true) + return result;// } + // throw new Error("Missing return statement in function"); + } + + @SuppressWarnings("unused") + Unit exponentExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + Exponent exponent = null; + Token token = null; + if (jj_2_2(2147483647)) { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INTEGER: + token = jj_consume_token(INTEGER); + break; + case E: + token = jj_consume_token(E); + break; + default: + jj_la1[5] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + jj_consume_token(CARET); + result = atomicExpr(); + double base; + if (token.kind == INTEGER) { + base = Integer.parseInt(token.image); + } else { + base = E; + } + { + if (true) + return result.transform(new LogConverter(base).inverse()); + } + } else { + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case OPEN_PAREN: + case INTEGER: + case FLOATING_POINT: + case UNIT_IDENTIFIER: + result = atomicExpr(); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CARET: + case SUPERSCRIPT_INTEGER: + exponent = exp(); + break; + default: + jj_la1[6] = jj_gen; + } + if (exponent != null) { + if (exponent.pow != 1) { + result = result.pow(exponent.pow); + } + if (exponent.root != 1) { + result = result.root(exponent.root); + } + } + { + if (true) + return result; + } + // break; + case LOG: + case NAT_LOG: + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case LOG: + jj_consume_token(LOG); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INTEGER: + token = jj_consume_token(INTEGER); + break; + default: + jj_la1[7] = jj_gen; + } + break; + case NAT_LOG: + token = jj_consume_token(NAT_LOG); + break; + default: + jj_la1[8] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + jj_consume_token(OPEN_PAREN); + result = addExpr(); + jj_consume_token(CLOSE_PAREN); + double base = 10; + if (token != null) { + if (token.kind == INTEGER) { + base = Integer.parseInt(token.image); + } else if (token.kind == NAT_LOG) { + base = E; + } + } + { + if (true) + return result.transform(new LogConverter(base)); + } + default: + jj_la1[9] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + } + throw new Error("Missing return statement in function"); + } + + Unit atomicExpr() throws TokenException { + Unit result = AbstractUnit.ONE; + // Unit temp = AbstractUnit.ONE; + Number n = null; + Token token = null; + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INTEGER: + case FLOATING_POINT: + n = numberExpr(); + if (n instanceof Integer) { + { + if (true) + return result.multiply(n.intValue()); + } + } else { + { + if (true) + return result.multiply(n.doubleValue()); + } + } + // break; + case UNIT_IDENTIFIER: + token = jj_consume_token(UNIT_IDENTIFIER); + Unit unit = symbols.getUnit(token.image); + if (unit == null) { + MetricPrefix prefix = symbols.getPrefix(token.image); + if (prefix != null) { + String prefixSymbol = symbols.getSymbol(prefix); + unit = symbols.getUnit(token.image.substring(prefixSymbol.length())); + if (unit != null) { + { + if (true) + return unit.transform(prefix.getConverter()); + } + } + } + { + if (true) + throw new TokenException(); + } + } else { + { + if (true) + return unit; + } + } + // break; + case OPEN_PAREN: + jj_consume_token(OPEN_PAREN); + result = addExpr(); + jj_consume_token(CLOSE_PAREN); + { + if (true) + return result; + } + // break; + default: + jj_la1[10] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + // throw new Error("Missing return statement in function"); + } + + @SuppressWarnings("unused") + Token sign() throws TokenException { + Token result = null; + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + result = jj_consume_token(PLUS); + break; + case MINUS: + result = jj_consume_token(MINUS); + break; + default: + jj_la1[11] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + { + if (true) + return result; + } + throw new Error("Missing return statement in function"); + } + + Number numberExpr() throws TokenException { + Token token = null; + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case INTEGER: + token = jj_consume_token(INTEGER); + { + if (true) + return Long.valueOf(token.image); + } + // break; + case FLOATING_POINT: + token = jj_consume_token(FLOATING_POINT); + { + if (true) + return Double.valueOf(token.image); + } + // break; + default: + jj_la1[12] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + // throw new Error("Missing return statement in function"); + } + + Exponent exp() throws TokenException { + Token powSign = null; + Token powToken = null; + Token rootSign = null; + Token rootToken = null; + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case CARET: + jj_consume_token(CARET); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + case INTEGER: + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + powSign = sign(); + break; + default: + jj_la1[13] = jj_gen; + } + powToken = jj_consume_token(INTEGER); + int pow = Integer.parseInt(powToken.image); + if ((powSign != null) && powSign.image.equals("-")) { + pow = -pow; + } + { + if (true) + return new Exponent(pow, 1); + } + case OPEN_PAREN: + jj_consume_token(OPEN_PAREN); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + powSign = sign(); + break; + default: + jj_la1[14] = jj_gen; + } + powToken = jj_consume_token(INTEGER); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case SOLIDUS: + jj_consume_token(SOLIDUS); + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { + case PLUS: + case MINUS: + rootSign = sign(); + break; + default: + jj_la1[15] = jj_gen; + } + rootToken = jj_consume_token(INTEGER); + break; + default: + jj_la1[16] = jj_gen; + } + jj_consume_token(CLOSE_PAREN); + pow = Integer.parseInt(powToken.image); + if ((powSign != null) && powSign.image.equals("-")) { + pow = -pow; + } + int root = 1; + if (rootToken != null) { + root = Integer.parseInt(rootToken.image); + if ((rootSign != null) && rootSign.image.equals("-")) { + root = -root; + } + } + { + if (true) + return new Exponent(pow, root); + } + default: + jj_la1[17] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + case SUPERSCRIPT_INTEGER: + powToken = jj_consume_token(SUPERSCRIPT_INTEGER); + int pow = 0; + for (int i = 0; i < powToken.image.length(); i += 1) { + pow *= 10; + switch (powToken.image.charAt(i)) { + case '\u00b9': + pow += 1; + break; + case '\u00b2': + pow += 2; + break; + case '\u00b3': + pow += 3; + break; + case '\u2074': + pow += 4; + break; + case '\u2075': + pow += 5; + break; + case '\u2076': + pow += 6; + break; + case '\u2077': + pow += 7; + break; + case '\u2078': + pow += 8; + break; + case '\u2079': + pow += 9; + break; + } + } + { + if (true) + return new Exponent(pow, 1); + } + // break; + default: + jj_la1[18] = jj_gen; + jj_consume_token(-1); + throw new TokenException(); + } + // throw new Error("Missing return statement in function"); + } + + private boolean jj_2_1(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_1(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(0, xla); + } + } + + private boolean jj_2_2(int xla) { + jj_la = xla; + jj_lastpos = jj_scanpos = token; + try { + return !jj_3_2(); + } catch (LookaheadSuccess ls) { + return true; + } finally { + jj_save(1, xla); + } + } + + private boolean jj_3R_3() { + Token xsp; + xsp = jj_scanpos; + if (jj_3R_5()) { + jj_scanpos = xsp; + if (jj_3R_6()) + return true; + } + return false; + } + + private boolean jj_3R_6() { + return jj_scan_token(FLOATING_POINT); + } + + private boolean jj_3_2() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(14)) { + jj_scanpos = xsp; + if (jj_scan_token(19)) + return true; + } + return jj_scan_token(CARET); + } + + private boolean jj_3_1() { + return jj_3R_3() || jj_3R_4(); + } + + private boolean jj_3R_4() { + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(5)) { + jj_scanpos = xsp; + if (jj_scan_token(6)) + return true; + } + return false; + } + + private boolean jj_3R_5() { + return jj_scan_token(INTEGER); + } + + /** Generated Token Manager. */ + private UnitTokenManager token_source; + private DefaultCharStream jj_input_stream; + /** Current token. */ + private Token token; + /** Next token. */ + private Token jj_nt; + private int jj_ntk; + private Token jj_scanpos, jj_lastpos; + private int jj_la; + private int jj_gen; + final private int[] jj_la1 = new int[19]; + static private int[] jj_la1_0; + static { + jj_la1_init_0(); + } + + private static void jj_la1_init_0() { + jj_la1_0 = new int[] { 0x800, 0x60, 0x380, 0x180, 0x380, 0x84000, 0x8400, 0x4000, 0x60000, 0x175000, 0x115000, 0x60, 0x14000, 0x60, 0x60, 0x60, + 0x200, 0x5060, 0x8400, }; + } + + final private JJCalls[] jj_2_rtns = new JJCalls[2]; + private boolean jj_rescan = false; + private int jj_gc = 0; + + /** Constructor with InputStream. */ + UnitFormatParser(java.io.InputStream stream) { + this(stream, null); + } + + /** Constructor with InputStream and supplied encoding */ + UnitFormatParser(java.io.InputStream stream, String encoding) { + try { + jj_input_stream = new DefaultCharStream(stream, encoding, 1, 1); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + token_source = new UnitTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 19; i++) + jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) + jj_2_rtns[i] = new JJCalls(); + } + + /** Constructor. */ + UnitFormatParser(java.io.Reader stream) { + jj_input_stream = new DefaultCharStream(stream, 1, 1); + token_source = new UnitTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 19; i++) + jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) + jj_2_rtns[i] = new JJCalls(); + } + + /** Reinitialise. */ + // private void reInit(java.io.Reader stream) { + // jj_input_stream.reInit(stream, 1, 1); + // token_source.reInit(jj_input_stream); + // token = new Token(); + // jj_ntk = -1; + // jj_gen = 0; + // for (int i = 0; i < 19; i++) jj_la1[i] = -1; + // for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + // } + + /** Constructor with generated Token Manager. */ + UnitFormatParser(UnitTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 19; i++) + jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) + jj_2_rtns[i] = new JJCalls(); + } + + /** Reinitialise. */ + // private void reInit(UnitTokenManager tm) { + // token_source = tm; + // token = new Token(); + // jj_ntk = -1; + // jj_gen = 0; + // for (int i = 0; i < 19; i++) jj_la1[i] = -1; + // for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + // } + + private Token jj_consume_token(int kind) throws TokenException { + Token oldToken; + if ((oldToken = token).next != null) + token = token.next; + else + token = token.next = token_source.getNextToken(); + jj_ntk = -1; + if (token.kind == kind) { + jj_gen++; + if (++jj_gc > 100) { + jj_gc = 0; + for (int i = 0; i < jj_2_rtns.length; i++) { + JJCalls c = jj_2_rtns[i]; + while (c != null) { + if (c.gen < jj_gen) + c.first = null; + c = c.next; + } + } + } + return token; + } + token = oldToken; + jj_kind = kind; + throw generateParseException(); + } + + static private final class LookaheadSuccess extends java.lang.Error { + /** * - */ - private static final long serialVersionUID = -8192240240676284081L; - } - - final private LookaheadSuccess jj_ls = new LookaheadSuccess(); - - private boolean jj_scan_token(int kind) { - if (jj_scanpos == jj_lastpos) { - jj_la--; - if (jj_scanpos.next == null) { - jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); - } else { - jj_lastpos = jj_scanpos = jj_scanpos.next; - } - } else { - jj_scanpos = jj_scanpos.next; - } - if (jj_rescan) { - int i = 0; - Token tok = token; - while (tok != null && tok != jj_scanpos) { - i++; - tok = tok.next; - } - if (tok != null) - jj_add_error_token(kind, i); - } - if (jj_scanpos.kind != kind) - return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) - throw jj_ls; - return false; - } - - /** Get the next Token. */ - final Token getNextToken() { - if (token.next != null) - token = token.next; - else - token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - /** Get the specific Token. */ - final Token getToken(int index) { - Token t = token; - for (int i = 0; i < index; i++) { - if (t.next != null) - t = t.next; - else - t = t.next = token_source.getNextToken(); - } - return t; - } - - private int jj_ntk() { - if ((jj_nt = token.next) == null) - return (jj_ntk = (token.next = token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private final java.util.List jj_expentries = new java.util.ArrayList<>(); - private int[] jj_expentry; - private int jj_kind = -1; - private int[] jj_lasttokens = new int[100]; - private int jj_endpos; - - private void jj_add_error_token(int kind, int pos) { - if (pos >= 100) - return; - if (pos == jj_endpos + 1) { - jj_lasttokens[jj_endpos++] = kind; - } else if (jj_endpos != 0) { - jj_expentry = new int[jj_endpos]; - System.arraycopy(jj_lasttokens, 0, jj_expentry, 0, jj_endpos); - jj_entries_loop: for (java.util.Iterator it = jj_expentries.iterator(); it.hasNext();) { - int[] oldentry = (int[]) (it.next()); - if (oldentry.length == jj_expentry.length) { - for (int i = 0; i < jj_expentry.length; i++) { - if (oldentry[i] != jj_expentry[i]) { - continue jj_entries_loop; - } - } - jj_expentries.add(jj_expentry); - break; - } - } - if (pos != 0) - jj_lasttokens[(jj_endpos = pos) - 1] = kind; - } - } - - /** Generate TokenException. */ - TokenException generateParseException() { - jj_expentries.clear(); - boolean[] la1tokens = new boolean[21]; - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 19; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1 << j)) != 0) { - la1tokens[j] = true; - } - } - } - } - for (int i = 0; i < 21; i++) { - if (la1tokens[i]) { - jj_expentry = new int[1]; - jj_expentry[0] = i; - jj_expentries.add(jj_expentry); - } - } - jj_endpos = 0; - jj_rescan_token(); - jj_add_error_token(0, 0); - int[][] exptokseq = new int[jj_expentries.size()][]; - for (int i = 0; i < jj_expentries.size(); i++) { - exptokseq[i] = jj_expentries.get(i); - } - return new TokenException(token, exptokseq, tokenImage); - } - - /** Enable tracing. */ - final void enable_tracing() { - } - - /** Disable tracing. */ - final void disable_tracing() { - } - - private void jj_rescan_token() { - jj_rescan = true; - for (int i = 0; i < 2; i++) { - try { - JJCalls p = jj_2_rtns[i]; - do { - if (p.gen > jj_gen) { - jj_la = p.arg; - jj_lastpos = jj_scanpos = p.first; - switch (i) { - case 0: - jj_3_1(); - break; - case 1: - jj_3_2(); - break; - } - } - p = p.next; - } while (p != null); - } catch (LookaheadSuccess ls) { - } - } - jj_rescan = false; - } - - private void jj_save(int index, int xla) { - JJCalls p = jj_2_rtns[index]; - while (p.gen > jj_gen) { - if (p.next == null) { - p = p.next = new JJCalls(); - break; - } - p = p.next; - } - p.gen = jj_gen + xla - jj_la; - p.first = token; - p.arg = xla; - } - - static final class JJCalls { - int gen; - Token first; - int arg; - JJCalls next; - } - -} + */ + private static final long serialVersionUID = -8192240240676284081L; + } + + final private LookaheadSuccess jj_ls = new LookaheadSuccess(); + + private boolean jj_scan_token(int kind) { + if (jj_scanpos == jj_lastpos) { + jj_la--; + if (jj_scanpos.next == null) { + jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); + } else { + jj_lastpos = jj_scanpos = jj_scanpos.next; + } + } else { + jj_scanpos = jj_scanpos.next; + } + if (jj_rescan) { + int i = 0; + Token tok = token; + while (tok != null && tok != jj_scanpos) { + i++; + tok = tok.next; + } + if (tok != null) + jj_add_error_token(kind, i); + } + if (jj_scanpos.kind != kind) + return true; + if (jj_la == 0 && jj_scanpos == jj_lastpos) + throw jj_ls; + return false; + } + + /** Get the next Token. */ + final Token getNextToken() { + if (token.next != null) + token = token.next; + else + token = token.next = token_source.getNextToken(); + jj_ntk = -1; + jj_gen++; + return token; + } + + /** Get the specific Token. */ + final Token getToken(int index) { + Token t = token; + for (int i = 0; i < index; i++) { + if (t.next != null) + t = t.next; + else + t = t.next = token_source.getNextToken(); + } + return t; + } + + private int jj_ntk() { + if ((jj_nt = token.next) == null) + return (jj_ntk = (token.next = token_source.getNextToken()).kind); + else + return (jj_ntk = jj_nt.kind); + } + + private final java.util.List jj_expentries = new java.util.ArrayList<>(); + private int[] jj_expentry; + private int jj_kind = -1; + private int[] jj_lasttokens = new int[100]; + private int jj_endpos; + + private void jj_add_error_token(int kind, int pos) { + if (pos >= 100) + return; + if (pos == jj_endpos + 1) { + jj_lasttokens[jj_endpos++] = kind; + } else if (jj_endpos != 0) { + jj_expentry = new int[jj_endpos]; + System.arraycopy(jj_lasttokens, 0, jj_expentry, 0, jj_endpos); + jj_entries_loop: for (java.util.Iterator it = jj_expentries.iterator(); it.hasNext();) { + int[] oldentry = (int[]) (it.next()); + if (oldentry.length == jj_expentry.length) { + for (int i = 0; i < jj_expentry.length; i++) { + if (oldentry[i] != jj_expentry[i]) { + continue jj_entries_loop; + } + } + jj_expentries.add(jj_expentry); + break; + } + } + if (pos != 0) + jj_lasttokens[(jj_endpos = pos) - 1] = kind; + } + } + + /** Generate TokenException. */ + TokenException generateParseException() { + jj_expentries.clear(); + boolean[] la1tokens = new boolean[21]; + if (jj_kind >= 0) { + la1tokens[jj_kind] = true; + jj_kind = -1; + } + for (int i = 0; i < 19; i++) { + if (jj_la1[i] == jj_gen) { + for (int j = 0; j < 32; j++) { + if ((jj_la1_0[i] & (1 << j)) != 0) { + la1tokens[j] = true; + } + } + } + } + for (int i = 0; i < 21; i++) { + if (la1tokens[i]) { + jj_expentry = new int[1]; + jj_expentry[0] = i; + jj_expentries.add(jj_expentry); + } + } + jj_endpos = 0; + jj_rescan_token(); + jj_add_error_token(0, 0); + int[][] exptokseq = new int[jj_expentries.size()][]; + for (int i = 0; i < jj_expentries.size(); i++) { + exptokseq[i] = jj_expentries.get(i); + } + return new TokenException(token, exptokseq, tokenImage); + } + + /** Enable tracing. */ + final void enable_tracing() { + } + + /** Disable tracing. */ + final void disable_tracing() { + } + + private void jj_rescan_token() { + jj_rescan = true; + for (int i = 0; i < 2; i++) { + try { + JJCalls p = jj_2_rtns[i]; + do { + if (p.gen > jj_gen) { + jj_la = p.arg; + jj_lastpos = jj_scanpos = p.first; + switch (i) { + case 0: + jj_3_1(); + break; + case 1: + jj_3_2(); + break; + } + } + p = p.next; + } while (p != null); + } catch (LookaheadSuccess ls) { + } + } + jj_rescan = false; + } + + private void jj_save(int index, int xla) { + JJCalls p = jj_2_rtns[index]; + while (p.gen > jj_gen) { + if (p.next == null) { + p = p.next = new JJCalls(); + break; + } + p = p.next; + } + p.gen = jj_gen + xla - jj_la; + p.first = token; + p.arg = xla; + } + + static final class JJCalls { + int gen; + Token first; + int arg; + JJCalls next; + } + +} diff --git a/src/main/java/tec/uom/se/internal/format/UnitTokenConstants.java b/src/main/java/tec/uom/se/internal/format/UnitTokenConstants.java index f17980d7..c850b87a 100644 --- a/src/main/java/tec/uom/se/internal/format/UnitTokenConstants.java +++ b/src/main/java/tec/uom/se/internal/format/UnitTokenConstants.java @@ -1,89 +1,89 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. UnitTokenConstants.java */ -package tec.uom.se.internal.format; - -/** - * Token literal values and constants. Generated by org.javacc.parser.OtherFilesGen#start() - */ -interface UnitTokenConstants { - - /** End of File. */ - int EOF = 0; - /** RegularExpression Id. */ - int DIGIT = 1; - /** RegularExpression Id. */ - int SUPERSCRIPT_DIGIT = 2; - /** RegularExpression Id. */ - int INITIAL_CHAR = 3; - /** RegularExpression Id. */ - int EXTENDED_CHAR = 4; - /** RegularExpression Id. */ - int PLUS = 5; - /** RegularExpression Id. */ - int MINUS = 6; - /** RegularExpression Id. */ - int ASTERISK = 7; - /** RegularExpression Id. */ - int MIDDLE_DOT = 8; - /** RegularExpression Id. */ - int SOLIDUS = 9; - /** RegularExpression Id. */ - int CARET = 10; - /** RegularExpression Id. */ - int COLON = 11; - /** RegularExpression Id. */ - int OPEN_PAREN = 12; - /** RegularExpression Id. */ - int CLOSE_PAREN = 13; - /** RegularExpression Id. */ - int INTEGER = 14; - /** RegularExpression Id. */ - int SUPERSCRIPT_INTEGER = 15; - /** RegularExpression Id. */ - int FLOATING_POINT = 16; - /** RegularExpression Id. */ - int LOG = 17; - /** RegularExpression Id. */ - int NAT_LOG = 18; - /** RegularExpression Id. */ - int E = 19; - /** RegularExpression Id. */ - int UNIT_IDENTIFIER = 20; - - /** Lexical state. */ - int DEFAULT = 0; - - /** Literal token values. */ - String[] tokenImage = { "", "", "", "", "", "\"+\"", "\"-\"", "\"*\"", "\"\\u00b7\"", - "\"/\"", "\"^\"", "\":\"", "\"(\"", "\")\"", "", "", "", "", "", "\"e\"", - "", }; - -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. UnitTokenConstants.java */ +package tec.uom.se.internal.format; + +/** + * Token literal values and constants. Generated by org.javacc.parser.OtherFilesGen#start() + */ +interface UnitTokenConstants { + + /** End of File. */ + int EOF = 0; + /** RegularExpression Id. */ + int DIGIT = 1; + /** RegularExpression Id. */ + int SUPERSCRIPT_DIGIT = 2; + /** RegularExpression Id. */ + int INITIAL_CHAR = 3; + /** RegularExpression Id. */ + int EXTENDED_CHAR = 4; + /** RegularExpression Id. */ + int PLUS = 5; + /** RegularExpression Id. */ + int MINUS = 6; + /** RegularExpression Id. */ + int ASTERISK = 7; + /** RegularExpression Id. */ + int MIDDLE_DOT = 8; + /** RegularExpression Id. */ + int SOLIDUS = 9; + /** RegularExpression Id. */ + int CARET = 10; + /** RegularExpression Id. */ + int COLON = 11; + /** RegularExpression Id. */ + int OPEN_PAREN = 12; + /** RegularExpression Id. */ + int CLOSE_PAREN = 13; + /** RegularExpression Id. */ + int INTEGER = 14; + /** RegularExpression Id. */ + int SUPERSCRIPT_INTEGER = 15; + /** RegularExpression Id. */ + int FLOATING_POINT = 16; + /** RegularExpression Id. */ + int LOG = 17; + /** RegularExpression Id. */ + int NAT_LOG = 18; + /** RegularExpression Id. */ + int E = 19; + /** RegularExpression Id. */ + int UNIT_IDENTIFIER = 20; + + /** Lexical state. */ + int DEFAULT = 0; + + /** Literal token values. */ + String[] tokenImage = { "", "", "", "", "", "\"+\"", "\"-\"", "\"*\"", "\"\\u00b7\"", + "\"/\"", "\"^\"", "\":\"", "\"(\"", "\")\"", "", "", "", "", "", "\"e\"", + "", }; + +} diff --git a/src/main/java/tec/uom/se/internal/format/UnitTokenManager.java b/src/main/java/tec/uom/se/internal/format/UnitTokenManager.java index 8e241d8c..64b6702e 100644 --- a/src/main/java/tec/uom/se/internal/format/UnitTokenManager.java +++ b/src/main/java/tec/uom/se/internal/format/UnitTokenManager.java @@ -1,461 +1,461 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* Generated By:JavaCC: Do not edit this line. UnitTokenManager.java */ -package tec.uom.se.internal.format; - -/** Token Manager. */ -final class UnitTokenManager { - - /** Debug output. */ - public java.io.PrintStream debugStream = System.out; - - /** Set debug output. */ - public void setDebugStream(java.io.PrintStream ds) { - debugStream = ds; - } - - private int jjStopStringLiteralDfa_0(int pos) { - switch (pos) { - default: - return -1; - } - } - - private int jjStartNfa_0(int pos, long active0) { - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos), pos + 1); - } - - private int jjStopAtPos(int pos, int kind) { - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; - } - - private int jjMoveStringLiteralDfa0_0() { - switch (curChar) { - case 40: - return jjStopAtPos(0, 12); - case 41: - return jjStopAtPos(0, 13); - case 42: - return jjStopAtPos(0, 7); - case 43: - return jjStopAtPos(0, 5); - case 45: - return jjStopAtPos(0, 6); - case 47: - return jjStopAtPos(0, 9); - case 58: - return jjStopAtPos(0, 11); - case 94: - return jjStopAtPos(0, 10); - case 101: - return jjStartNfaWithStates_0(0, 19, 7); - case 183: - return jjStopAtPos(0, 8); - default: - return jjMoveNfa_0(6, 0); - } - } - - private int jjStartNfaWithStates_0(int pos, int kind, int state) { - jjmatchedKind = kind; - jjmatchedPos = pos; - try { - curChar = input_stream.readChar(); - } catch (java.io.IOException e) { - return pos + 1; - } - return jjMoveNfa_0(state, pos + 1); - } - - static final long[] jjbitVec0 = { 0x0L, 0x0L, 0x20c000000000000L, 0x0L }; - static final long[] jjbitVec1 = { 0x0L, 0x3f1000000000000L, 0x0L, 0x0L }; - static final long[] jjbitVec2 = { 0xfffffffefffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; - static final long[] jjbitVec4 = { 0x0L, 0x0L, 0xfd73ffffffffffffL, 0xffffffffffffffffL }; - static final long[] jjbitVec5 = { 0xffffffffffffffffL, 0xfc0effffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; - - private int jjMoveNfa_0(int startState, int curPos) { - int startsAt = 0; - jjnewStateCnt = 15; - int i = 1; - jjstateSet[0] = startState; - int kind = 0x7fffffff; - for (;;) { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) { - long l = 1L << curChar; - do { - switch (jjstateSet[--i]) { - case 6: - if ((0xf80010fe00000000L & l) != 0L) { - if (kind > 20) - kind = 20; - jjCheckNAdd(7); - } else if ((0x3ff000000000000L & l) != 0L) { - if (kind > 14) - kind = 14; - jjCheckNAddStates(0, 4); - } else if (curChar == 46) - jjCheckNAdd(2); - break; - case 1: - if (curChar == 46) - jjCheckNAdd(2); - break; - case 2: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 16) - kind = 16; - jjCheckNAddTwoStates(2, 3); - break; - case 4: - if ((0x280000000000L & l) != 0L) - jjCheckNAdd(5); - break; - case 5: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 16) - kind = 16; - jjCheckNAdd(5); - break; - case 7: - if ((0xfbff10fe00000000L & l) == 0L) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(7); - break; - case 8: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 14) - kind = 14; - jjCheckNAddStates(0, 4); - break; - case 9: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 14) - kind = 14; - jjCheckNAdd(9); - break; - case 10: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 16) - kind = 16; - jjCheckNAddStates(5, 8); - break; - default: - break; - } - } while (i != startsAt); - } else if (curChar < 128) { - long l = 1L << (curChar & 63); - do { - switch (jjstateSet[--i]) { - case 6: - if ((0xffffffffbfffffffL & l) != 0L) { - if (kind > 20) - kind = 20; - jjCheckNAdd(7); - } - if (curChar == 108) - jjAddStates(9, 10); - break; - case 3: - if ((0x2000000020L & l) != 0L) - jjAddStates(11, 12); - break; - case 7: - if ((0xffffffffbfffffffL & l) == 0L) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(7); - break; - case 11: - if (curChar == 108) - jjAddStates(9, 10); - break; - case 12: - if (curChar == 111) - jjstateSet[jjnewStateCnt++] = 13; - break; - case 13: - if (curChar == 103 && kind > 17) - kind = 17; - break; - case 14: - if (curChar == 110 && kind > 18) - kind = 18; - break; - default: - break; - } - } while (i != startsAt); - } else { - int hiByte = curChar >> 8; - int i1 = hiByte >> 6; - long l1 = 1L << (hiByte & 63); - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 63); - do { - switch (jjstateSet[--i]) { - case 6: - if (jjCanMove_0(hiByte, i2, l2)) { - if (kind > 15) - kind = 15; - jjCheckNAdd(0); - } - if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { - if (kind > 20) - kind = 20; - jjCheckNAdd(7); - } - break; - case 0: - if (!jjCanMove_0(hiByte, i2, l2)) - break; - if (kind > 15) - kind = 15; - jjCheckNAdd(0); - break; - case 7: - if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(7); - break; - default: - break; - } - } while (i != startsAt); - } - if (kind != 0x7fffffff) { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 15 - (jjnewStateCnt = startsAt))) - return curPos; - try { - curChar = input_stream.readChar(); - } catch (java.io.IOException e) { - return curPos; - } - } - } - - static final int[] jjnextStates = { 9, 1, 2, 3, 10, 1, 2, 3, 10, 12, 14, 4, 5, }; - - private static boolean jjCanMove_0(int hiByte, int i2, long l2) { - switch (hiByte) { - case 0: - return ((jjbitVec0[i2] & l2) != 0L); - case 32: - return ((jjbitVec1[i2] & l2) != 0L); - default: - return false; - } - } - - private static boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) { - switch (hiByte) { - case 0: - return ((jjbitVec4[i2] & l2) != 0L); - case 32: - return ((jjbitVec5[i2] & l2) != 0L); - default: - return (jjbitVec2[i1] & l1) != 0L; - } - } - - /** Token literal values. */ - public static final String[] jjstrLiteralImages = { "", null, null, null, null, "\53", "\55", "\52", "\267", "\57", "\136", "\72", "\50", "\51", - null, null, null, null, null, "\145", null, }; - - /** Lexer state names. */ - public static final String[] lexStateNames = { "DEFAULT", }; - protected DefaultCharStream input_stream; - private final int[] jjrounds = new int[15]; - private final int[] jjstateSet = new int[30]; - protected char curChar; - - /** Constructor. */ - public UnitTokenManager(DefaultCharStream stream) { - if (DefaultCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; - } - - /** Constructor. */ - public UnitTokenManager(DefaultCharStream stream, int lexState) { - this(stream); - SwitchTo(lexState); - } - - /** Reinitialise parser. */ - public void ReInit(DefaultCharStream stream) { - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); - } - - private void ReInitRounds() { - int i; - jjround = 0x80000001; - for (i = 15; i-- > 0;) - jjrounds[i] = 0x80000000; - } - - /** Reinitialise parser. */ - public void ReInit(DefaultCharStream stream, int lexState) { - ReInit(stream); - SwitchTo(lexState); - } - - /** Switch to specified lex state. */ - public void SwitchTo(int lexState) { - if (lexState >= 1 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; - } - - protected Token jjFillToken() { - final Token t; - final String curTokenImage; - final int beginLine; - final int endLine; - final int beginColumn; - final int endColumn; - String im = jjstrLiteralImages[jjmatchedKind]; - curTokenImage = (im == null) ? input_stream.GetImage() : im; - beginLine = input_stream.getBeginLine(); - beginColumn = input_stream.getBeginColumn(); - endLine = input_stream.getEndLine(); - endColumn = input_stream.getEndColumn(); - t = Token.newToken(jjmatchedKind, curTokenImage); - - t.beginLine = beginLine; - t.endLine = endLine; - t.beginColumn = beginColumn; - t.endColumn = endColumn; - - return t; - } - - int curLexState = 0; - final int defaultLexState = 0; - int jjnewStateCnt; - int jjround; - int jjmatchedPos; - int jjmatchedKind; - - /** Get the next Token. */ - public Token getNextToken() { - Token matchedToken; - int curPos = 0; - - EOFLoop: for (;;) { - try { - curChar = input_stream.BeginToken(); - } catch (java.io.IOException e) { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - return matchedToken; - } - - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - if (jjmatchedKind != 0x7fffffff) { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - matchedToken = jjFillToken(); - return matchedToken; - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { - input_stream.readChar(); - input_stream.backup(1); - } catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } - } - - private void jjCheckNAdd(int state) { - if (jjrounds[state] != jjround) { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } - } - - private void jjAddStates(int start, int end) { - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); - } - - private void jjCheckNAddTwoStates(int state1, int state2) { - jjCheckNAdd(state1); - jjCheckNAdd(state2); - } - - private void jjCheckNAddStates(int start, int end) { - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); - } - -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* Generated By:JavaCC: Do not edit this line. UnitTokenManager.java */ +package tec.uom.se.internal.format; + +/** Token Manager. */ +final class UnitTokenManager { + + /** Debug output. */ + public java.io.PrintStream debugStream = System.out; + + /** Set debug output. */ + public void setDebugStream(java.io.PrintStream ds) { + debugStream = ds; + } + + private int jjStopStringLiteralDfa_0(int pos) { + switch (pos) { + default: + return -1; + } + } + + private int jjStartNfa_0(int pos, long active0) { + return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos), pos + 1); + } + + private int jjStopAtPos(int pos, int kind) { + jjmatchedKind = kind; + jjmatchedPos = pos; + return pos + 1; + } + + private int jjMoveStringLiteralDfa0_0() { + switch (curChar) { + case 40: + return jjStopAtPos(0, 12); + case 41: + return jjStopAtPos(0, 13); + case 42: + return jjStopAtPos(0, 7); + case 43: + return jjStopAtPos(0, 5); + case 45: + return jjStopAtPos(0, 6); + case 47: + return jjStopAtPos(0, 9); + case 58: + return jjStopAtPos(0, 11); + case 94: + return jjStopAtPos(0, 10); + case 101: + return jjStartNfaWithStates_0(0, 19, 7); + case 183: + return jjStopAtPos(0, 8); + default: + return jjMoveNfa_0(6, 0); + } + } + + private int jjStartNfaWithStates_0(int pos, int kind, int state) { + jjmatchedKind = kind; + jjmatchedPos = pos; + try { + curChar = input_stream.readChar(); + } catch (java.io.IOException e) { + return pos + 1; + } + return jjMoveNfa_0(state, pos + 1); + } + + static final long[] jjbitVec0 = { 0x0L, 0x0L, 0x20c000000000000L, 0x0L }; + static final long[] jjbitVec1 = { 0x0L, 0x3f1000000000000L, 0x0L, 0x0L }; + static final long[] jjbitVec2 = { 0xfffffffefffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; + static final long[] jjbitVec4 = { 0x0L, 0x0L, 0xfd73ffffffffffffL, 0xffffffffffffffffL }; + static final long[] jjbitVec5 = { 0xffffffffffffffffL, 0xfc0effffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; + + private int jjMoveNfa_0(int startState, int curPos) { + int startsAt = 0; + jjnewStateCnt = 15; + int i = 1; + jjstateSet[0] = startState; + int kind = 0x7fffffff; + for (;;) { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) { + long l = 1L << curChar; + do { + switch (jjstateSet[--i]) { + case 6: + if ((0xf80010fe00000000L & l) != 0L) { + if (kind > 20) + kind = 20; + jjCheckNAdd(7); + } else if ((0x3ff000000000000L & l) != 0L) { + if (kind > 14) + kind = 14; + jjCheckNAddStates(0, 4); + } else if (curChar == 46) + jjCheckNAdd(2); + break; + case 1: + if (curChar == 46) + jjCheckNAdd(2); + break; + case 2: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 16) + kind = 16; + jjCheckNAddTwoStates(2, 3); + break; + case 4: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(5); + break; + case 5: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 16) + kind = 16; + jjCheckNAdd(5); + break; + case 7: + if ((0xfbff10fe00000000L & l) == 0L) + break; + if (kind > 20) + kind = 20; + jjCheckNAdd(7); + break; + case 8: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 14) + kind = 14; + jjCheckNAddStates(0, 4); + break; + case 9: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 14) + kind = 14; + jjCheckNAdd(9); + break; + case 10: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 16) + kind = 16; + jjCheckNAddStates(5, 8); + break; + default: + break; + } + } while (i != startsAt); + } else if (curChar < 128) { + long l = 1L << (curChar & 63); + do { + switch (jjstateSet[--i]) { + case 6: + if ((0xffffffffbfffffffL & l) != 0L) { + if (kind > 20) + kind = 20; + jjCheckNAdd(7); + } + if (curChar == 108) + jjAddStates(9, 10); + break; + case 3: + if ((0x2000000020L & l) != 0L) + jjAddStates(11, 12); + break; + case 7: + if ((0xffffffffbfffffffL & l) == 0L) + break; + if (kind > 20) + kind = 20; + jjCheckNAdd(7); + break; + case 11: + if (curChar == 108) + jjAddStates(9, 10); + break; + case 12: + if (curChar == 111) + jjstateSet[jjnewStateCnt++] = 13; + break; + case 13: + if (curChar == 103 && kind > 17) + kind = 17; + break; + case 14: + if (curChar == 110 && kind > 18) + kind = 18; + break; + default: + break; + } + } while (i != startsAt); + } else { + int hiByte = curChar >> 8; + int i1 = hiByte >> 6; + long l1 = 1L << (hiByte & 63); + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 63); + do { + switch (jjstateSet[--i]) { + case 6: + if (jjCanMove_0(hiByte, i2, l2)) { + if (kind > 15) + kind = 15; + jjCheckNAdd(0); + } + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { + if (kind > 20) + kind = 20; + jjCheckNAdd(7); + } + break; + case 0: + if (!jjCanMove_0(hiByte, i2, l2)) + break; + if (kind > 15) + kind = 15; + jjCheckNAdd(0); + break; + case 7: + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) + break; + if (kind > 20) + kind = 20; + jjCheckNAdd(7); + break; + default: + break; + } + } while (i != startsAt); + } + if (kind != 0x7fffffff) { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 15 - (jjnewStateCnt = startsAt))) + return curPos; + try { + curChar = input_stream.readChar(); + } catch (java.io.IOException e) { + return curPos; + } + } + } + + static final int[] jjnextStates = { 9, 1, 2, 3, 10, 1, 2, 3, 10, 12, 14, 4, 5, }; + + private static boolean jjCanMove_0(int hiByte, int i2, long l2) { + switch (hiByte) { + case 0: + return ((jjbitVec0[i2] & l2) != 0L); + case 32: + return ((jjbitVec1[i2] & l2) != 0L); + default: + return false; + } + } + + private static boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) { + switch (hiByte) { + case 0: + return ((jjbitVec4[i2] & l2) != 0L); + case 32: + return ((jjbitVec5[i2] & l2) != 0L); + default: + return (jjbitVec2[i1] & l1) != 0L; + } + } + + /** Token literal values. */ + public static final String[] jjstrLiteralImages = { "", null, null, null, null, "\53", "\55", "\52", "\267", "\57", "\136", "\72", "\50", "\51", + null, null, null, null, null, "\145", null, }; + + /** Lexer state names. */ + public static final String[] lexStateNames = { "DEFAULT", }; + protected DefaultCharStream input_stream; + private final int[] jjrounds = new int[15]; + private final int[] jjstateSet = new int[30]; + protected char curChar; + + /** Constructor. */ + public UnitTokenManager(DefaultCharStream stream) { + if (DefaultCharStream.staticFlag) + throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); + input_stream = stream; + } + + /** Constructor. */ + public UnitTokenManager(DefaultCharStream stream, int lexState) { + this(stream); + SwitchTo(lexState); + } + + /** Reinitialise parser. */ + public void ReInit(DefaultCharStream stream) { + jjmatchedPos = jjnewStateCnt = 0; + curLexState = defaultLexState; + input_stream = stream; + ReInitRounds(); + } + + private void ReInitRounds() { + int i; + jjround = 0x80000001; + for (i = 15; i-- > 0;) + jjrounds[i] = 0x80000000; + } + + /** Reinitialise parser. */ + public void ReInit(DefaultCharStream stream, int lexState) { + ReInit(stream); + SwitchTo(lexState); + } + + /** Switch to specified lex state. */ + public void SwitchTo(int lexState) { + if (lexState >= 1 || lexState < 0) + throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); + else + curLexState = lexState; + } + + protected Token jjFillToken() { + final Token t; + final String curTokenImage; + final int beginLine; + final int endLine; + final int beginColumn; + final int endColumn; + String im = jjstrLiteralImages[jjmatchedKind]; + curTokenImage = (im == null) ? input_stream.GetImage() : im; + beginLine = input_stream.getBeginLine(); + beginColumn = input_stream.getBeginColumn(); + endLine = input_stream.getEndLine(); + endColumn = input_stream.getEndColumn(); + t = Token.newToken(jjmatchedKind, curTokenImage); + + t.beginLine = beginLine; + t.endLine = endLine; + t.beginColumn = beginColumn; + t.endColumn = endColumn; + + return t; + } + + int curLexState = 0; + final int defaultLexState = 0; + int jjnewStateCnt; + int jjround; + int jjmatchedPos; + int jjmatchedKind; + + /** Get the next Token. */ + public Token getNextToken() { + Token matchedToken; + int curPos = 0; + + EOFLoop: for (;;) { + try { + curChar = input_stream.BeginToken(); + } catch (java.io.IOException e) { + jjmatchedKind = 0; + matchedToken = jjFillToken(); + return matchedToken; + } + + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_0(); + if (jjmatchedKind != 0x7fffffff) { + if (jjmatchedPos + 1 < curPos) + input_stream.backup(curPos - jjmatchedPos - 1); + matchedToken = jjFillToken(); + return matchedToken; + } + int error_line = input_stream.getEndLine(); + int error_column = input_stream.getEndColumn(); + String error_after = null; + boolean EOFSeen = false; + try { + input_stream.readChar(); + input_stream.backup(1); + } catch (java.io.IOException e1) { + EOFSeen = true; + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + if (curChar == '\n' || curChar == '\r') { + error_line++; + error_column = 0; + } else + error_column++; + } + if (!EOFSeen) { + input_stream.backup(1); + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + } + throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); + } + } + + private void jjCheckNAdd(int state) { + if (jjrounds[state] != jjround) { + jjstateSet[jjnewStateCnt++] = state; + jjrounds[state] = jjround; + } + } + + private void jjAddStates(int start, int end) { + do { + jjstateSet[jjnewStateCnt++] = jjnextStates[start]; + } while (start++ != end); + } + + private void jjCheckNAddTwoStates(int state1, int state2) { + jjCheckNAdd(state1); + jjCheckNAdd(state2); + } + + private void jjCheckNAddStates(int start, int end) { + do { + jjCheckNAdd(jjnextStates[start]); + } while (start++ != end); + } + +} diff --git a/src/main/java/tec/uom/se/internal/format/l10n/BundleToMapAdapter.java b/src/main/java/tec/uom/se/internal/format/l10n/BundleToMapAdapter.java index 380708c2..4a81c42c 100644 --- a/src/main/java/tec/uom/se/internal/format/l10n/BundleToMapAdapter.java +++ b/src/main/java/tec/uom/se/internal/format/l10n/BundleToMapAdapter.java @@ -1,72 +1,72 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.internal.format.l10n; - -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.ResourceBundle; - -/** - * - * @author Werner Keil - * @version 0.3, February 15, 2015 - * - */ -public final class BundleToMapAdapter { - public static Map toMap(final ResourceBundle resource) { - Map map = new HashMap<>(); - - Enumeration keys = resource.getKeys(); - while (keys.hasMoreElements()) { - String key = keys.nextElement(); - map.put(key, resource.getString(key)); - } - - return map; - } - - // public final static Map toMap(final MapResourceBundle - // resource) { - // Map map = new HashMap<>(); - // - // Enumeration keys = resource.getKeys(); - // while (keys.hasMoreElements()) { - // String key = keys.nextElement(); - // map.put(key, resource.getString(key)); - // } - // - // return map; - // } - - public static Map toMap(String resName) { - return toMap(ResourceBundle.getBundle(resName)); - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.internal.format.l10n; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.ResourceBundle; + +/** + * + * @author Werner Keil + * @version 0.3, February 15, 2015 + * + */ +public final class BundleToMapAdapter { + public static Map toMap(final ResourceBundle resource) { + Map map = new HashMap<>(); + + Enumeration keys = resource.getKeys(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + map.put(key, resource.getString(key)); + } + + return map; + } + + // public final static Map toMap(final MapResourceBundle + // resource) { + // Map map = new HashMap<>(); + // + // Enumeration keys = resource.getKeys(); + // while (keys.hasMoreElements()) { + // String key = keys.nextElement(); + // map.put(key, resource.getString(key)); + // } + // + // return map; + // } + + public static Map toMap(String resName) { + return toMap(ResourceBundle.getBundle(resName)); + } +} diff --git a/src/main/java/tec/uom/se/internal/format/l10n/MultiPropertyResourceBundle.java b/src/main/java/tec/uom/se/internal/format/l10n/MultiPropertyResourceBundle.java index 9e4a28fc..6b16030b 100644 --- a/src/main/java/tec/uom/se/internal/format/l10n/MultiPropertyResourceBundle.java +++ b/src/main/java/tec/uom/se/internal/format/l10n/MultiPropertyResourceBundle.java @@ -1,210 +1,210 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.internal.format.l10n; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.PropertyResourceBundle; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.Vector; - -/** - * Extends ResourceBundle with 2 new capabilities. The first is to store the path where the properties file used to create the - * InputStream is located and the second is to allow additional ResourceBundle properties to be merged into an instance. - *

- *

- * To allow a SystemOfUnits to locate and merge extension module properties files. - *

- * - * @author Werner Keil - */ -public class MultiPropertyResourceBundle extends ResourceBundle { - - /** - *

- * The location of the properties file that was used to instantiate the MultiPropertyResourceBundle instance. This field is set by the - * constructor. - *

- */ - private String resourcePath = null; - - /** - * @return The location of the properties file that was used to instantiate the MultiPropertyResourceBundle instance. - */ - public String getResourcePath() { - return resourcePath; - } - - /** - *

- * A {@link Map} containing all the properties that have been merged from multiple {@link ResourceBundle} instances. - *

- */ - private final Map resources = new HashMap<>(); - - /** - *

- * A {@link StringBuilder} instance containing all the paths of the {@link ResourceBundle} instances that have been merged into this instance. This - * value is intended to be use to help generate a key for caching JSON formatted resource output in the {@link AbstractWebScript} class. - *

- */ - private final StringBuilder mergedBundlePaths = new StringBuilder(); - - /** - * @return Returns the {@link StringBuilder} instance containing the paths of all the {@link ResourceBundle} instances that have been merged into - * this instance. - */ - public StringBuilder getMergedBundlePaths() { - return mergedBundlePaths; - } - - /** - *

- * Instantiates a new MultiPropertyResourceBundle. - *

- * - * @param stream - * The InputStream passed on to the super class constructor. - * @param resourcePath - * The location of the properties file used to create the InputStream - * @throws IOException - */ - public MultiPropertyResourceBundle(InputStream stream, String resourcePath) throws IOException { - final ResourceBundle resourceBundle = new PropertyResourceBundle(stream); - this.resourcePath = resourcePath; - merge(resourceBundle, resourcePath); - } - - /** - *

- * Constructor for instantiating from an existing {@link ResourceBundle}. This calls the merge method to copy the properties from the - * bundle into the resources map. - * - * @param baseBundle - * @param resourcePath - */ - public MultiPropertyResourceBundle(ResourceBundle baseBundle, String resourcePath) { - super(); - this.resourcePath = resourcePath; - merge(baseBundle, resourcePath); - } - - /** - *

- * Merges the properties of a ResourceBundle into the current MultiPropertyResourceBundle instance. This will override any - * values mapped to duplicate keys in the current merged properties. - *

- * - * @param resourceBundle - * The ResourceBundle to merge the properties of. - * @param resourcePath - */ - public void merge(ResourceBundle resourceBundle, String resourcePath) { - if (resourceBundle != null) { - Enumeration keys = resourceBundle.getKeys(); - while (keys.hasMoreElements()) { - String key = keys.nextElement(); - this.resources.put(key, resourceBundle.getObject(key)); - } - } - - // Update the paths merged in this bundle - mergedBundlePaths.append(resourcePath); - mergedBundlePaths.append(":"); - } - - /** - *

- * Overrides the super class implementation to return an object located in the merged bundles - *

- * - * @return An Object from the merged bundles - */ - @Override - public Object handleGetObject(String key) { - if (key == null) { - throw new NullPointerException(); - } - return this.resources.get(key); - } - - /** - *

- * Overrides the super class implementation to return an enumeration of keys from all the merged bundles - *

- * - * @return An Enumeration of the keys across all the merged bundles. - */ - @Override - public Enumeration getKeys() { - Vector keys = new Vector<>(this.resources.keySet()); - return keys.elements(); - } - - /** - *

- * Overrides the super class implementation to return the Set of keys from all merged bundles - *

- * - * @return A Set of keys obtained from all merged bundles - */ - @Override - protected Set handleKeySet() { - return this.resources.keySet(); - } - - /** - *

- * Overrides the super class implementation to check the existence of a key across all merged bundles - *

- * - * @return true if the key is present and false otherwise. - */ - @Override - public boolean containsKey(String key) { - return this.resources.containsKey(key); - } - - /** - *

- * Overrides the super class implementation to return the Set of keys from all merged bundles - *

- * - * @return A Set of keys obtained from all merged bundles - */ - @Override - public Set keySet() { - return this.resources.keySet(); - } -} +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.internal.format.l10n; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.Vector; + +/** + * Extends ResourceBundle with 2 new capabilities. The first is to store the path where the properties file used to create the + * InputStream is located and the second is to allow additional ResourceBundle properties to be merged into an instance. + *

+ *

+ * To allow a SystemOfUnits to locate and merge extension module properties files. + *

+ * + * @author Werner Keil + */ +public class MultiPropertyResourceBundle extends ResourceBundle { + + /** + *

+ * The location of the properties file that was used to instantiate the MultiPropertyResourceBundle instance. This field is set by the + * constructor. + *

+ */ + private String resourcePath = null; + + /** + * @return The location of the properties file that was used to instantiate the MultiPropertyResourceBundle instance. + */ + public String getResourcePath() { + return resourcePath; + } + + /** + *

+ * A {@link Map} containing all the properties that have been merged from multiple {@link ResourceBundle} instances. + *

+ */ + private final Map resources = new HashMap<>(); + + /** + *

+ * A {@link StringBuilder} instance containing all the paths of the {@link ResourceBundle} instances that have been merged into this instance. This + * value is intended to be use to help generate a key for caching JSON formatted resource output in the {@link AbstractWebScript} class. + *

+ */ + private final StringBuilder mergedBundlePaths = new StringBuilder(); + + /** + * @return Returns the {@link StringBuilder} instance containing the paths of all the {@link ResourceBundle} instances that have been merged into + * this instance. + */ + public StringBuilder getMergedBundlePaths() { + return mergedBundlePaths; + } + + /** + *

+ * Instantiates a new MultiPropertyResourceBundle. + *

+ * + * @param stream + * The InputStream passed on to the super class constructor. + * @param resourcePath + * The location of the properties file used to create the InputStream + * @throws IOException + */ + public MultiPropertyResourceBundle(InputStream stream, String resourcePath) throws IOException { + final ResourceBundle resourceBundle = new PropertyResourceBundle(stream); + this.resourcePath = resourcePath; + merge(resourceBundle, resourcePath); + } + + /** + *

+ * Constructor for instantiating from an existing {@link ResourceBundle}. This calls the merge method to copy the properties from the + * bundle into the resources map. + * + * @param baseBundle + * @param resourcePath + */ + public MultiPropertyResourceBundle(ResourceBundle baseBundle, String resourcePath) { + super(); + this.resourcePath = resourcePath; + merge(baseBundle, resourcePath); + } + + /** + *

+ * Merges the properties of a ResourceBundle into the current MultiPropertyResourceBundle instance. This will override any + * values mapped to duplicate keys in the current merged properties. + *

+ * + * @param resourceBundle + * The ResourceBundle to merge the properties of. + * @param resourcePath + */ + public void merge(ResourceBundle resourceBundle, String resourcePath) { + if (resourceBundle != null) { + Enumeration keys = resourceBundle.getKeys(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + this.resources.put(key, resourceBundle.getObject(key)); + } + } + + // Update the paths merged in this bundle + mergedBundlePaths.append(resourcePath); + mergedBundlePaths.append(":"); + } + + /** + *

+ * Overrides the super class implementation to return an object located in the merged bundles + *

+ * + * @return An Object from the merged bundles + */ + @Override + public Object handleGetObject(String key) { + if (key == null) { + throw new NullPointerException(); + } + return this.resources.get(key); + } + + /** + *

+ * Overrides the super class implementation to return an enumeration of keys from all the merged bundles + *

+ * + * @return An Enumeration of the keys across all the merged bundles. + */ + @Override + public Enumeration getKeys() { + Vector keys = new Vector<>(this.resources.keySet()); + return keys.elements(); + } + + /** + *

+ * Overrides the super class implementation to return the Set of keys from all merged bundles + *

+ * + * @return A Set of keys obtained from all merged bundles + */ + @Override + protected Set handleKeySet() { + return this.resources.keySet(); + } + + /** + *

+ * Overrides the super class implementation to check the existence of a key across all merged bundles + *

+ * + * @return true if the key is present and false otherwise. + */ + @Override + public boolean containsKey(String key) { + return this.resources.containsKey(key); + } + + /** + *

+ * Overrides the super class implementation to return the Set of keys from all merged bundles + *

+ * + * @return A Set of keys obtained from all merged bundles + */ + @Override + public Set keySet() { + return this.resources.keySet(); + } +} diff --git a/src/main/java/tec/uom/se/internal/format/l10n/ResourceBundleEnumeration.java b/src/main/java/tec/uom/se/internal/format/l10n/ResourceBundleEnumeration.java index f6b49f32..190cef38 100644 --- a/src/main/java/tec/uom/se/internal/format/l10n/ResourceBundleEnumeration.java +++ b/src/main/java/tec/uom/se/internal/format/l10n/ResourceBundleEnumeration.java @@ -1,100 +1,100 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tec.uom.se.internal.format.l10n; - -import java.io.Serializable; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Set; - -/** - * Implements an Enumeration that combines elements from a Set and an Enumeration. Used by {@link MultiPropertyResourceBundle}. - */ -class ResourceBundleEnumeration implements Serializable, Enumeration { - - /** - * For serialize. - */ - private static final long serialVersionUID = -1259498757256943174L; - - private Set set; - private Iterator iterator; - private Enumeration enumeration; - private String next = null; - - /** - * Constructor. - */ - public ResourceBundleEnumeration() { - super(); - } - - /** - * Constructs a resource bundle enumeration. - * - * @param set - * a set providing some elements of the enumeration - * @param enumeration - * an enumeration providing more elements of the enumeration. enumeration may be null. - */ - ResourceBundleEnumeration(Set set, Enumeration enumeration) { - this.set = set; - this.iterator = set.iterator(); - this.enumeration = enumeration; - } - - public boolean hasMoreElements() { - if (next == null) { - if (iterator.hasNext()) { - next = iterator.next(); - } else if (enumeration != null) { - while (next == null && enumeration.hasMoreElements()) { - next = enumeration.nextElement(); - if (set.contains(next)) { - next = null; - } - } - } - } - return next != null; - } - - public String nextElement() { - if (hasMoreElements()) { - String result = next; - next = null; - return result; - } else { - throw new NoSuchElementException(); - } - } - +/* + * Units of Measurement Implementation for Java SE + * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tec.uom.se.internal.format.l10n; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * Implements an Enumeration that combines elements from a Set and an Enumeration. Used by {@link MultiPropertyResourceBundle}. + */ +class ResourceBundleEnumeration implements Serializable, Enumeration { + + /** + * For serialize. + */ + private static final long serialVersionUID = -1259498757256943174L; + + private Set set; + private Iterator iterator; + private Enumeration enumeration; + private String next = null; + + /** + * Constructor. + */ + public ResourceBundleEnumeration() { + super(); + } + + /** + * Constructs a resource bundle enumeration. + * + * @param set + * a set providing some elements of the enumeration + * @param enumeration + * an enumeration providing more elements of the enumeration. enumeration may be null. + */ + ResourceBundleEnumeration(Set set, Enumeration enumeration) { + this.set = set; + this.iterator = set.iterator(); + this.enumeration = enumeration; + } + + public boolean hasMoreElements() { + if (next == null) { + if (iterator.hasNext()) { + next = iterator.next(); + } else if (enumeration != null) { + while (next == null && enumeration.hasMoreElements()) { + next = enumeration.nextElement(); + if (set.contains(next)) { + next = null; + } + } + } + } + return next != null; + } + + public String nextElement() { + if (hasMoreElements()) { + String result = next; + next = null; + return result; + } else { + throw new NoSuchElementException(); + } + } + } \ No newline at end of file diff --git a/src/main/java/tec/uom/se/package-info.java b/src/main/java/tec/uom/se/package-info.java index f492fc6c..44f8ee8b 100644 --- a/src/main/java/tec/uom/se/package-info.java +++ b/src/main/java/tec/uom/se/package-info.java @@ -1,110 +1,110 @@ -/* - * Units of Measurement Implementation for Java SE - * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/** - * This package provides a Java SE 8 implementation of the - * Units of Measurement API. - * - * - *

Usage:

- * - * - * import javax.measure.quantity.*; // Holds quantity types. - * - * import tec.uom.se.AbstractUnit; - * import tec.uom.se.function.AbstractConverter; - * - * import static tec.uom.se.unit.Units.*; // Standard CommonUnits. - * import static tec.uom.se.unit.MetricPrefix.*; - * import static tec.uom.se.spi.UCUM.*; // Standard & Non-Standard CommonUnits. - * - * public class Main { - * public void main(String[] args) { - * - * // Conversion between units (explicit way). - * AbstractUnit sourceUnit = KILO(METRE); - * AbstractUnit targetUnit = MILE; - * PhysicsConverter uc = sourceUnit.getConverterTo(targetUnit); - * System.out.println(uc.convert(10)); // Converts 10 km to miles. - * - * // Same conversion than above, packed in one line. - * System.out.println(KILO(METRE).getConverterTo(MILE).convert(10)); - * - * // Retrieval of the SI unit (identifies the measurement type). - * System.out.println(REVOLUTION.divide(MINUTE).toSI()); - * - * // Dimension checking (allows/disallows conversions) - * System.out.println(ELECTRON_VOLT.isCompatible(WATT.times(HOUR))); - * - * // Retrieval of the unit dimension (depends upon the current model). - * System.out.println(ELECTRON_VOLT.getDimension()); - * } - * } - * - * > 6.2137119223733395 - * > 6.2137119223733395 - * > rad/s - * > true - * > [L]²·[M]/[T]² - * - * - *

Unit Parameterization

- * - * CommonUnits are parameterized enforce compile-time checks of units/measures consistency, for example:[code] - * - * AbstractUnit