X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=common%2Fyang-common%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fcommon%2FDecimal64.java;h=c91e42f417935de228eca5f743cfbb06747c1c9b;hb=a468678519c5b5390892997917cd3935f683a657;hp=2f2de8837a755bfd7d889de6b05074645da2460e;hpb=685a4aad1c4d27a355dcec8b862e60bfc101ce9c;p=yangtools.git diff --git a/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java b/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java index 2f2de8837a..c91e42f417 100644 --- a/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java +++ b/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java @@ -14,6 +14,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -140,7 +141,7 @@ public class Decimal64 extends Number implements CanonicalValue { private static final int MAX_SCALE = 18; - private static final long[] SCALE = { + private static final long[] FACTOR = { 10, 100, 1000, @@ -161,28 +162,46 @@ public class Decimal64 extends Number implements CanonicalValue { 1000000000000000000L }; + private static final Decimal64Conversion[] CONVERSION = Decimal64Conversion.values(); + private static final Decimal64[] MIN_VALUE; + private static final Decimal64[] MAX_VALUE; + static { - verify(SCALE.length == MAX_SCALE); + verify(CONVERSION.length == MAX_SCALE); + verify(FACTOR.length == MAX_SCALE); + + MIN_VALUE = new Decimal64[MAX_SCALE]; + MAX_VALUE = new Decimal64[MAX_SCALE]; + for (byte i = 0; i < MAX_SCALE; ++i) { + MIN_VALUE[i] = new Decimal64(i, -9223372036854775808L); + MAX_VALUE[i] = new Decimal64(i, 9223372036854775807L); + } } - private final byte scaleOffset; + private final byte offset; private final long value; @VisibleForTesting Decimal64(final int scale, final long intPart, final long fracPart, final boolean negative) { - scaleOffset = offsetOf(scale); + offset = offsetOf(scale); - final long bits = intPart * SCALE[scaleOffset] + fracPart; + final long bits = intPart * FACTOR[offset] + fracPart; value = negative ? -bits : bits; } - private Decimal64(final byte scaleOffset, final long value) { - this.scaleOffset = scaleOffset; + private Decimal64(final byte offset, final long intPart, final boolean negative) { + this.offset = offset; + final long bits = intPart * FACTOR[offset]; + value = negative ? -bits : bits; + } + + private Decimal64(final byte offset, final long value) { + this.offset = offset; this.value = value; } protected Decimal64(final Decimal64 other) { - this(other.scaleOffset, other.value); + this(other.offset, other.value); } /** @@ -197,29 +216,80 @@ public class Decimal64 extends Number implements CanonicalValue { return new Decimal64(offsetOf(scale), unscaledValue); } - // >>> FIXME: these need to take a scale value and perform a range check. we also need truncating counterparts - public static Decimal64 valueOf(final byte byteVal) { - return byteVal < 0 ? new Decimal64(1, -byteVal, 0, true) : new Decimal64(1, byteVal, 0, false); + /** + * Return the minimum value supported in specified scale. + * + * @param scale scale to use + * @return Minimum value in that scale + * @throws IllegalArgumentException if {@code scale} is not in range {@code [1..18]} + */ + public static Decimal64 minValueIn(final int scale) { + return MIN_VALUE[offsetOf(scale)]; + } + + /** + * Return the maximum value supported in specified scale. + * + * @param scale scale to use + * @return Maximum value in that scale + * @throws IllegalArgumentException if {@code scale} is not in range {@code [1..18]} + */ + public static Decimal64 maxValueIn(final int scale) { + return MAX_VALUE[offsetOf(scale)]; + } + + // >>> FIXME: these need truncating counterparts + public static Decimal64 valueOf(final int scale, final byte byteVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (byteVal < conv.minByte || byteVal > conv.maxByte) { + throw new IllegalArgumentException("Value " + byteVal + " is not in range [" + + conv.minByte + ".." + conv.maxByte + "] to fit scale " + scale); + } + return byteVal < 0 ? new Decimal64(offset, -byteVal, true) : new Decimal64(offset, byteVal, false); + } + + public static Decimal64 valueOf(final int scale, final short shortVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (shortVal < conv.minShort || shortVal > conv.maxShort) { + throw new IllegalArgumentException("Value " + shortVal + " is not in range [" + + conv.minShort + ".." + conv.maxShort + "] to fit scale " + scale); + } + return shortVal < 0 ? new Decimal64(offset, -shortVal, true) : new Decimal64(offset, shortVal, false); } - public static Decimal64 valueOf(final short shortVal) { - return shortVal < 0 ? new Decimal64(1, -shortVal, 0, true) : new Decimal64(1, shortVal, 0, false); + public static Decimal64 valueOf(final int scale, final int intVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (intVal < conv.minInt || intVal > conv.maxInt) { + throw new IllegalArgumentException("Value " + intVal + " is not in range [" + + conv.minInt + ".." + conv.maxInt + "] to fit scale " + scale); + } + return intVal < 0 ? new Decimal64(offset, - (long)intVal, true) : new Decimal64(offset, intVal, false); } - public static Decimal64 valueOf(final int intVal) { - return intVal < 0 ? new Decimal64(1, - (long)intVal, 0, true) : new Decimal64(1, intVal, 0, false); + public static Decimal64 valueOf(final int scale, final long longVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (longVal < conv.minLong || longVal > conv.maxLong) { + throw new IllegalArgumentException("Value " + longVal + " is not in range [" + + conv.minLong + ".." + conv.maxLong + "] to fit scale " + scale); + } + return longVal < 0 ? new Decimal64(offset, -longVal, true) : new Decimal64(offset, longVal, false); } + // <<< FIXME - public static Decimal64 valueOf(final long longVal) { + // FIXME: this should take a RoundingMode and perform rounding + // FIXME: this should have a truncating counterpart + public static Decimal64 valueOf(final float floatVal, final RoundingMode rounding) { // XXX: we should be able to do something smarter here - return valueOf(Long.toString(longVal)); + return valueOf(Float.toString(floatVal)); } - // <<< FIXME // FIXME: this should take a RoundingMode and perform rounding - // FIXME: this should have a float counterpart - // FIXME: this should have a truncating - public static Decimal64 valueOf(final double doubleVal) { + // FIXME: this should have a truncating counterpart + public static Decimal64 valueOf(final double doubleVal, final RoundingMode rounding) { // XXX: we should be able to do something smarter here return valueOf(Double.toString(doubleVal)); } @@ -254,7 +324,7 @@ public class Decimal64 extends Number implements CanonicalValue { * @return This decimal's scale */ public final int scale() { - return scaleOffset + 1; + return offset + 1; } /** @@ -287,7 +357,7 @@ public class Decimal64 extends Number implements CanonicalValue { @Override public final double doubleValue() { - return 1.0 * value / SCALE[scaleOffset]; + return 1.0 * value / FACTOR[offset]; } /** @@ -361,7 +431,7 @@ public class Decimal64 extends Number implements CanonicalValue { if (this == o) { return 0; } - if (scaleOffset == o.scaleOffset) { + if (offset == o.offset) { return Long.compare(value, o.value); } @@ -422,17 +492,17 @@ public class Decimal64 extends Number implements CanonicalValue { } private boolean equalsImpl(final Decimal64 other) { - return scaleOffset == other.scaleOffset ? value == other.value + return offset == other.offset ? value == other.value // We need to normalize both : intPart() == other.intPart() && fracPart() == other.fracPart(); } private long intPart() { - return value / SCALE[scaleOffset]; + return value / FACTOR[offset]; } private long fracPart() { - return Math.abs(value % SCALE[scaleOffset]); + return Math.abs(value % FACTOR[offset]); } private static byte offsetOf(final int scale) {