X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-common%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fcommon%2FDecimal64.java;h=78354f391594807493c9ff3d191ca9265c75b13c;hb=464009b3dbd29d24d2d64744a5e10b8722f90562;hp=5fba2e0e3fe8e700c621d38f3e90c770a3707ade;hpb=3599e380a5330d9cf31f1919fbf9ec3dbf73c852;p=yangtools.git diff --git a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java index 5fba2e0e3f..78354f3915 100644 --- a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java +++ b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java @@ -14,8 +14,10 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import java.math.BigDecimal; +import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.yangtools.concepts.Variant; /** * Dedicated type for YANG's 'type decimal64' type. This class is similar to {@link BigDecimal}, but provides more @@ -26,14 +28,110 @@ import org.eclipse.jdt.annotation.Nullable; @Beta @NonNullByDefault public class Decimal64 extends Number implements CanonicalValue { - private static final class Support extends AbstractCanonicalValueSupport { - Support() { + public static final class Support extends AbstractCanonicalValueSupport { + public Support() { super(Decimal64.class); } @Override - public Decimal64 fromString(final String str) { - return Decimal64.valueOf(str); + public Variant fromString(final String str) { + // https://tools.ietf.org/html/rfc6020#section-9.3.1 + // + // A decimal64 value is lexically represented as an optional sign ("+" + // or "-"), followed by a sequence of decimal digits, optionally + // followed by a period ('.') as a decimal indicator and a sequence of + // decimal digits. If no sign is specified, "+" is assumed. + if (str.isEmpty()) { + return CanonicalValueViolation.variantOf("Empty string is not a valid decimal64 representation"); + } + + // Deal with optional sign + final boolean negative; + int idx; + switch (str.charAt(0)) { + case '-': + negative = true; + idx = 1; + break; + case '+': + negative = false; + idx = 1; + break; + default: + negative = false; + idx = 0; + } + + // Sanity check length + if (idx == str.length()) { + return CanonicalValueViolation.variantOf("Missing digits after sign"); + } + + // Character limit, used for caching and cutting trailing zeroes + int limit = str.length() - 1; + + // Skip any leading zeroes, but leave at least one + for (; idx < limit && str.charAt(idx) == '0'; idx++) { + final char ch = str.charAt(idx + 1); + if (ch < '0' || ch > '9') { + break; + } + } + + // Integer part and its length + int intLen = 0; + long intPart = 0; + + for (; idx <= limit; idx++, intLen++) { + final char ch = str.charAt(idx); + if (ch == '.') { + // Fractions are next + break; + } + if (intLen == MAX_FRACTION_DIGITS) { + return CanonicalValueViolation.variantOf( + "Integer part is longer than " + MAX_FRACTION_DIGITS + " digits"); + } + + intPart = 10 * intPart + toInt(ch, idx); + } + + if (idx > limit) { + // No fraction digits, we are done + return Variant.ofFirst(new Decimal64((byte)1, intPart, 0, negative)); + } + + // Bump index to skip over period and check the remainder + idx++; + if (idx > limit) { + return CanonicalValueViolation.variantOf("Value '" + str + "' is missing fraction digits"); + } + + // Trim trailing zeroes, if any + while (idx < limit && str.charAt(limit) == '0') { + limit--; + } + + final int fracLimit = MAX_FRACTION_DIGITS - intLen; + byte fracLen = 0; + long fracPart = 0; + for (; idx <= limit; idx++, fracLen++) { + final char ch = str.charAt(idx); + if (fracLen == fracLimit) { + return CanonicalValueViolation.variantOf("Fraction part longer than " + fracLimit + " digits"); + } + + fracPart = 10 * fracPart + toInt(ch, idx); + } + + return Variant.ofFirst(new Decimal64(fracLen, intPart, fracPart, negative)); + } + + private static int toInt(final char ch, final int index) { + if (ch < '0' || ch > '9') { + throw new NumberFormatException("Illegal character at offset " + index); + } + return ch - '0'; } } @@ -121,95 +219,13 @@ public class Decimal64 extends Number implements CanonicalValue { * @throws NumberFormatException if the string does not contain a parsable decimal64. */ public static Decimal64 valueOf(final String str) { - // https://tools.ietf.org/html/rfc6020#section-9.3.1 - // - // A decimal64 value is lexically represented as an optional sign ("+" - // or "-"), followed by a sequence of decimal digits, optionally - // followed by a period ('.') as a decimal indicator and a sequence of - // decimal digits. If no sign is specified, "+" is assumed. - if (str.isEmpty()) { - throw new NumberFormatException("Empty string is not a valid decimal64 representation"); - } - - // Deal with optional sign - final boolean negative; - int idx; - switch (str.charAt(0)) { - case '-': - negative = true; - idx = 1; - break; - case '+': - negative = false; - idx = 1; - break; - default: - negative = false; - idx = 0; - } - - // Sanity check length - if (idx == str.length()) { - throw new NumberFormatException("Missing digits after sign"); + final Variant variant = SUPPORT.fromString(str); + final Optional value = variant.tryFirst(); + if (value.isPresent()) { + return value.get(); } - - // Character limit, used for caching and cutting trailing zeroes - int limit = str.length() - 1; - - // Skip any leading zeroes, but leave at least one - for (; idx < limit && str.charAt(idx) == '0'; idx++) { - final char ch = str.charAt(idx + 1); - if (ch < '0' || ch > '9') { - break; - } - } - - // Integer part and its length - int intLen = 0; - long intPart = 0; - - for (; idx <= limit; idx++, intLen++) { - final char ch = str.charAt(idx); - if (ch == '.') { - // Fractions are next - break; - } - if (intLen == MAX_FRACTION_DIGITS) { - throw new NumberFormatException("Integer part is longer than " + MAX_FRACTION_DIGITS + " digits"); - } - - intPart = 10 * intPart + toInt(ch, idx); - } - - if (idx > limit) { - // No fraction digits, we are done - return new Decimal64((byte)1, intPart, 0, negative); - } - - // Bump index to skip over period and check the remainder - idx++; - if (idx > limit) { - throw new NumberFormatException("Value '" + str + "' is missing fraction digits"); - } - - // Trim trailing zeroes, if any - while (idx < limit && str.charAt(limit) == '0') { - limit--; - } - - final int fracLimit = MAX_FRACTION_DIGITS - intLen; - byte fracLen = 0; - long fracPart = 0; - for (; idx <= limit; idx++, fracLen++) { - final char ch = str.charAt(idx); - if (fracLen == fracLimit) { - throw new NumberFormatException("Fraction part longer than " + fracLimit + " digits"); - } - - fracPart = 10 * fracPart + toInt(ch, idx); - } - - return new Decimal64(fracLen, intPart, fracPart, negative); + final Optional message = variant.getSecond().getMessage(); + throw message.isPresent() ? new NumberFormatException(message.get()) : new NumberFormatException(); } public final BigDecimal decimalValue() { @@ -349,19 +365,17 @@ public class Decimal64 extends Number implements CanonicalValue { @Override public final boolean equals(final @Nullable Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Decimal64)) { - return false; - } - final Decimal64 other = (Decimal64) obj; - if (scaleOffset == other.scaleOffset) { - return value == other.value; - } + return this == obj || obj instanceof Decimal64 && equalsImpl((Decimal64) obj); + } - // We need to normalize both - return intPart() == other.intPart() && fracPart() == fracPart(); + /** + * A slightly faster version of {@link #equals(Object)}. + * + * @param obj Decimal64 object + * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. + */ + public final boolean equals(final @Nullable Decimal64 obj) { + return this == obj || obj != null && equalsImpl(obj); } @Override @@ -369,6 +383,12 @@ public class Decimal64 extends Number implements CanonicalValue { return toCanonicalString(); } + private boolean equalsImpl(final Decimal64 other) { + return scaleOffset == other.scaleOffset ? value == other.value + // We need to normalize both + : intPart() == other.intPart() && fracPart() == other.fracPart(); + } + private long intPart() { return value / SCALE[scaleOffset]; } @@ -376,11 +396,4 @@ public class Decimal64 extends Number implements CanonicalValue { private long fracPart() { return Math.abs(value % SCALE[scaleOffset]); } - - private static int toInt(final char ch, final int index) { - if (ch < '0' || ch > '9') { - throw new NumberFormatException("Illegal character at offset " + index); - } - return ch - '0'; - } }