1- // SPDX-FileCopyright: Copyright 2018 Firebird development team and individual contributors
1+ // SPDX-FileCopyright: Copyright 2018-2026 Firebird development team and individual contributors
22// SPDX-FileContributor: Mark Rotteveel
33// SPDX-License-Identifier: MIT
44package org .firebirdsql .extern .decimal ;
55
66import java .math .BigDecimal ;
77import java .math .BigInteger ;
88import java .math .MathContext ;
9- import java .util .Locale ;
109import java .util .Objects ;
1110
1211import static java .util .Objects .requireNonNull ;
1615 *
1716 * @author Mark Rotteveel
1817 */
19- public abstract class Decimal <T extends Decimal <T >> {
18+ public abstract sealed class Decimal <T extends Decimal <T >> permits Decimal32 , Decimal64 , Decimal128 {
2019
2120 private final int signum ;
2221 private final DecimalType type ;
2322 private final BigDecimal bigDecimal ;
2423
2524 Decimal (int signum , DecimalType type ) {
25+ //noinspection ConstantValue
2626 assert type != null : "Type should not be null" ;
2727 assert type != DecimalType .FINITE : "Constructor only suitable for non-FINITE" ;
2828 assert -1 == signum || signum == 1 : "Invalid signum, " + signum ;
2929 this .signum = signum ;
3030 this .type = type ;
31- bigDecimal = null ;
31+ bigDecimal = BigDecimal . ZERO ;
3232 }
3333
3434 Decimal (int signum , BigDecimal bigDecimal ) {
@@ -70,21 +70,12 @@ public final BigDecimal toBigDecimal() {
7070 * @return this decimal converted to a {@code double}
7171 */
7272 public final double doubleValue () {
73- switch (type ) {
74- case FINITE :
75- return bigDecimal .doubleValue ();
76-
77- case INFINITY :
78- return signum == Signum .NEGATIVE ? Double .NEGATIVE_INFINITY : Double .POSITIVE_INFINITY ;
79-
80- case NAN :
81- case SIGNALING_NAN :
73+ return switch (type ) {
74+ case FINITE -> bigDecimal .doubleValue ();
75+ case INFINITY -> signum == Signum .NEGATIVE ? Double .NEGATIVE_INFINITY : Double .POSITIVE_INFINITY ;
8276 // No differentiation between positive/negative and signaling/normal
83- return Double .NaN ;
84-
85- default :
86- throw new IllegalStateException ("Unsupported DecimalType " + type );
87- }
77+ case NAN , SIGNALING_NAN -> Double .NaN ;
78+ };
8879 }
8980
9081 /**
@@ -186,25 +177,17 @@ final T negate() {
186177
187178 @ Override
188179 public final String toString () {
189- switch (type ) {
190- case FINITE :
191- if (signum == Signum .NEGATIVE && isEquivalentToZero ()) {
192- return "-" + bigDecimal .toString ();
180+ return switch (type ) {
181+ case FINITE -> {
182+ if (signum == Signum .NEGATIVE && isEquivalentToZero ()) {
183+ yield "-" + bigDecimal ;
184+ }
185+ yield bigDecimal .toString ();
193186 }
194- return bigDecimal .toString ();
195-
196- case INFINITY :
197- return signum == Signum .NEGATIVE ? "-Infinity" : "+Infinity" ;
198-
199- case NAN :
200- return signum == Signum .NEGATIVE ? "-NaN" : "+NaN" ;
201-
202- case SIGNALING_NAN :
203- return signum == Signum .NEGATIVE ? "-sNaN" : "+sNaN" ;
204-
205- default :
206- throw new IllegalStateException ("Unsupported DecimalType " + type );
207- }
187+ case INFINITY -> signum == Signum .NEGATIVE ? "-Infinity" : "+Infinity" ;
188+ case NAN -> signum == Signum .NEGATIVE ? "-NaN" : "+NaN" ;
189+ case SIGNALING_NAN -> signum == Signum .NEGATIVE ? "-sNaN" : "+sNaN" ;
190+ };
208191 }
209192
210193 @ Override
@@ -223,7 +206,7 @@ public final boolean equals(Object o) {
223206 public final int hashCode () {
224207 int result = signum ;
225208 result = 31 * result + type .hashCode ();
226- result = 31 * result + ( bigDecimal != null ? bigDecimal .hashCode () : 0 );
209+ result = 31 * result + bigDecimal .hashCode ();
227210 return result ;
228211 }
229212
@@ -320,10 +303,11 @@ final T valueOf(BigInteger value, OverflowHandling overflowHandling) {
320303 /**
321304 * Creates a decimal from {@code value}, rejecting values that would lose precision due to rounding.
322305 *
323- * @param value Big integer value to convert
306+ * @param value
307+ * Big integer value to convert
308+ * @return Decimal equivalent
324309 * @throws DecimalOverflowException
325310 * If the value is out of range.
326- * @return Decimal equivalent
327311 * @see #valueOf(BigInteger, OverflowHandling)
328312 */
329313 final T valueOfExact (BigInteger value ) {
@@ -337,7 +321,8 @@ final T valueOfExact(BigInteger value) {
337321 * {@code Double.NaN} is mapped to positive NaN, the infinities to their equivalent +/- infinity.
338322 * </p>
339323 * <p>
340- * For normal, finite, values, this is equivalent to {@code valueOf(BigDecimal.valueOf(value), overflowHandling)}.
324+ * For normal, finite, values, this is equivalent to
325+ * {@code valueOf(BigDecimal.valueOf(value), overflowHandling)}.
341326 * </p>
342327 *
343328 * @param value
@@ -363,8 +348,8 @@ final T valueOf(double value, OverflowHandling overflowHandling) {
363348 /**
364349 * Converts a decimal to this type.
365350 * <p>
366- * For normal, finite, decimals, this behaves like {@code valueOf(decimal.toBigDecimal(), overflowHandling)}, see
367- * {@link #valueOf(BigDecimal, OverflowHandling)}.
351+ * For normal, finite, decimals, this behaves like {@code valueOf(decimal.toBigDecimal(), overflowHandling)},
352+ * see {@link #valueOf(BigDecimal, OverflowHandling)}.
368353 * </p>
369354 *
370355 * @param decimal
@@ -388,7 +373,7 @@ final T valueOf(Decimal<?> decimal, OverflowHandling overflowHandling) {
388373 /**
389374 * Creates a decimal from {@code value}, applying rounding where necessary.
390375 * <p>
391- * Except for the special values [+/-]Inf, [+/-]Infinity, [+/-]NaN and [+/-]sNaN (case insensitive), the rules
376+ * Except for the special values [+/-]Inf, [+/-]Infinity, [+/-]NaN and [+/-]sNaN (case- insensitive), the rules
392377 * of {@link BigDecimal#BigDecimal(String)} apply, with special handling in place to discern between positive
393378 * and negative zero.
394379 * </p>
@@ -421,65 +406,40 @@ final T valueOf(String value, OverflowHandling overflowHandling) {
421406 BigDecimal bdValue = new BigDecimal (value , getMathContext ());
422407 T decimalValue = valueOf (bdValue , overflowHandling );
423408 if (decimalValue .isEquivalentToZero ()
424- && value .charAt (0 ) == '-'
425- && bdValue .signum () != Signum .NEGATIVE ) {
409+ && value .charAt (0 ) == '-'
410+ && bdValue .signum () != Signum .NEGATIVE ) {
426411 return decimalValue .negate ();
427412 }
428413 return decimalValue ;
429414 }
430415
431416 private T valueOfSpecial (String special ) {
432- switch (special .toLowerCase (Locale .ROOT )) {
433- case "inf" :
434- case "infinity" :
435- case "+inf" :
436- case "+infinity" :
437- return getSpecialConstant (Signum .POSITIVE , DecimalType .INFINITY );
438-
439- case "-inf" :
440- case "-infinity" :
441- return getSpecialConstant (Signum .NEGATIVE , DecimalType .INFINITY );
442-
443- case "nan" :
444- case "+nan" :
445- return getSpecialConstant (Signum .POSITIVE , DecimalType .NAN );
446-
447- case "-nan" :
448- return getSpecialConstant (Signum .NEGATIVE , DecimalType .NAN );
449-
450- case "snan" :
451- case "+snan" :
452- return getSpecialConstant (Signum .POSITIVE , DecimalType .SIGNALING_NAN );
453-
454- case "-snan" :
455- return getSpecialConstant (Signum .NEGATIVE , DecimalType .SIGNALING_NAN );
456-
457- default :
458- throw new NumberFormatException ("Invalid value " + special );
459- }
417+ return switch (special .toLowerCase ()) {
418+ case "inf" , "infinity" , "+inf" , "+infinity" ->
419+ getSpecialConstant (Signum .POSITIVE , DecimalType .INFINITY );
420+ case "-inf" , "-infinity" -> getSpecialConstant (Signum .NEGATIVE , DecimalType .INFINITY );
421+ case "nan" , "+nan" -> getSpecialConstant (Signum .POSITIVE , DecimalType .NAN );
422+ case "-nan" -> getSpecialConstant (Signum .NEGATIVE , DecimalType .NAN );
423+ case "snan" , "+snan" -> getSpecialConstant (Signum .POSITIVE , DecimalType .SIGNALING_NAN );
424+ case "-snan" -> getSpecialConstant (Signum .NEGATIVE , DecimalType .SIGNALING_NAN );
425+ default -> throw new NumberFormatException ("Invalid value " + special );
426+ };
460427 }
461428
462429 @ Override
463430 public final T getSpecialConstant (int signum , DecimalType decimalType ) {
464- switch (decimalType ) {
465- case INFINITY :
466- return signum == Signum .NEGATIVE
431+ return switch (decimalType ) {
432+ case INFINITY -> signum == Signum .NEGATIVE
467433 ? negativeInfinity
468434 : positiveInfinity ;
469-
470- case NAN :
471- return signum == Signum .NEGATIVE
435+ case NAN -> signum == Signum .NEGATIVE
472436 ? negativeNan
473437 : positiveNan ;
474-
475- case SIGNALING_NAN :
476- return signum == Signum .NEGATIVE
438+ case SIGNALING_NAN -> signum == Signum .NEGATIVE
477439 ? negativeSignalingNaN
478440 : positiveSignalingNaN ;
479-
480- default :
481- throw new AssertionError ("Invalid special value for decimalType " + decimalType );
482- }
441+ default -> throw new AssertionError ("Invalid special value for decimalType " + decimalType );
442+ };
483443 }
484444
485445 }
0 commit comments