| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package freemarker.ext.beans; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| |
| import freemarker.template.TemplateNumberModel; |
| import freemarker.template.utility.ClassUtil; |
| import freemarker.template.utility.NumberUtil; |
| |
| /** |
| * Everything related to coercion to ambiguous numerical types. |
| */ |
| class OverloadedNumberUtil { |
| |
| // Can't be instantiated |
| private OverloadedNumberUtil() { } |
| |
| /** |
| * The lower limit of conversion prices where there's a risk of significant mantissa loss. |
| * The value comes from misc/overloadedNumberRules/prices.ods and generator.ftl. |
| */ |
| static final int BIG_MANTISSA_LOSS_PRICE = 4 * 10000; |
| |
| /** The highest long that can be stored in double without precision loss: 2**53. */ |
| private static final long MAX_DOUBLE_OR_LONG = 9007199254740992L; |
| /** The lowest long that can be stored in double without precision loss: -(2**53). */ |
| private static final long MIN_DOUBLE_OR_LONG = -9007199254740992L; |
| private static final int MAX_DOUBLE_OR_LONG_LOG_2 = 53; |
| |
| /** The highest long that can be stored in float without precision loss: 2**24. */ |
| private static final int MAX_FLOAT_OR_INT = 16777216; |
| /** The lowest long that can be stored in float without precision loss: -(2**24). */ |
| private static final int MIN_FLOAT_OR_INT = -16777216; |
| private static final int MAX_FLOAT_OR_INT_LOG_2 = 24; |
| /** Lowest number that we don't thread as possible integer 0. */ |
| private static final double LOWEST_ABOVE_ZERO = 0.000001; |
| /** Highest number that we don't thread as possible integer 1. */ |
| private static final double HIGHEST_BELOW_ONE = 0.999999; |
| |
| /** |
| * Attaches the lowest alternative number type to the parameter number via {@link NumberWithFallbackType}, if |
| * that's useful according the possible target number types. This transformation is applied on the method call |
| * argument list before overloaded method selection. |
| * |
| * <p>Note that as of this writing, this method is only used when |
| * {@link BeansWrapper#getIncompatibleImprovements()} >= 2.3.21. |
| * |
| * <p>Why's this needed, how it works: Overloaded method selection only selects methods where the <em>type</em> |
| * (not the value!) of the argument is "smaller" or the same as the parameter type. This is similar to how it's in |
| * the Java language. That it only decides based on the parameter type is important because this way |
| * {@link OverloadedMethodsSubset} can cache method lookup decisions using the types as the cache key. Problem is, |
| * since you don't declare the exact numerical types in FTL, and FTL has only a single generic numeric type |
| * anyway, what Java type a {@link TemplateNumberModel} uses internally is often seen as a technical detail of which |
| * the template author can't always keep track of. So we investigate the <em>value</em> of the number too, |
| * then coerce it down without overflow to a type that will match the most overloaded methods. (This |
| * is especially important as FTL often stores numbers in {@link BigDecimal}-s, which will hardly ever match any |
| * method parameters.) We could simply return that number, like {@code Byte(0)} for an {@code Integer(0)}, |
| * however, then we would lose the information about what the original type was. The original type is sometimes |
| * important, as in ambiguous situations the method where there's an exact type match should be selected (like, |
| * when someone wants to select an overload explicitly with {@code m(x?int)}). Also, if an overload wins where |
| * the parameter type at the position of the number is {@code Number} or {@code Object} (or {@code Comparable} |
| * etc.), it's expected that we pass in the original value (an {@code Integer} in this example), especially if that |
| * value is the return value of another Java method. That's why we use |
| * {@link NumberWithFallbackType} numerical classes like {@link IntegerOrByte}, which represents both the original |
| * type and the coerced type, all encoded into the class of the value, which is used as the overloaded method lookup |
| * cache key. |
| * |
| * <p>See also: <tt>src\main\misc\overloadedNumberRules\prices.ods</tt>. |
| * |
| * @param num the number to coerce |
| * @param typeFlags the type flags of the target parameter position; see {@link TypeFlags} |
| * |
| * @returns The original number or a {@link NumberWithFallbackType}, depending on the actual value and the types |
| * indicated in the {@code targetNumTypes} parameter. |
| */ |
| static Number addFallbackType(final Number num, final int typeFlags) { |
| final Class numClass = num.getClass(); |
| if (numClass == BigDecimal.class) { |
| // For now we only support the backward-compatible mode that doesn't prevent roll overs and magnitude loss. |
| // However, we push the overloaded selection to the right direction, so we will at least indicate if the |
| // number has decimals. |
| BigDecimal n = (BigDecimal) num; |
| if ((typeFlags & TypeFlags.MASK_KNOWN_INTEGERS) != 0 |
| && (typeFlags & TypeFlags.MASK_KNOWN_NONINTEGERS) != 0 |
| && NumberUtil.isIntegerBigDecimal(n) /* <- can be expensive */) { |
| return new IntegerBigDecimal(n); |
| } else { |
| // Either it was a non-integer, or it didn't mater what it was, as we don't have both integer and |
| // non-integer target types. |
| return n; |
| } |
| } else if (numClass == Integer.class) { |
| int pn = num.intValue(); |
| // Note that we try to return the most specific type (i.e., the numerical type with the smallest range), but |
| // only among the types that are possible targets. Like if the only target is int and the value is 1, we |
| // will return Integer 1, not Byte 1, even though byte is automatically converted to int so it would |
| // work too. Why we avoid unnecessarily specific types is that they generate more overloaded method lookup |
| // cache entries, since the cache key is the array of the types of the argument values. So we want as few |
| // permutations as possible. |
| if ((typeFlags & TypeFlags.BYTE) != 0 && pn <= Byte.MAX_VALUE && pn >= Byte.MIN_VALUE) { |
| return new IntegerOrByte((Integer) num, (byte) pn); |
| } else if ((typeFlags & TypeFlags.SHORT) != 0 && pn <= Short.MAX_VALUE && pn >= Short.MIN_VALUE) { |
| return new IntegerOrShort((Integer) num, (short) pn); |
| } else { |
| return num; |
| } |
| } else if (numClass == Long.class) { |
| final long pn = num.longValue(); |
| if ((typeFlags & TypeFlags.BYTE) != 0 && pn <= Byte.MAX_VALUE && pn >= Byte.MIN_VALUE) { |
| return new LongOrByte((Long) num, (byte) pn); |
| } else if ((typeFlags & TypeFlags.SHORT) != 0 && pn <= Short.MAX_VALUE && pn >= Short.MIN_VALUE) { |
| return new LongOrShort((Long) num, (short) pn); |
| } else if ((typeFlags & TypeFlags.INTEGER) != 0 && pn <= Integer.MAX_VALUE && pn >= Integer.MIN_VALUE) { |
| return new LongOrInteger((Long) num, (int) pn); |
| } else { |
| return num; |
| } |
| } else if (numClass == Double.class) { |
| final double doubleN = num.doubleValue(); |
| |
| // Can we store it in an integer type? |
| checkIfWholeNumber: do { |
| if ((typeFlags & TypeFlags.MASK_KNOWN_INTEGERS) == 0) break checkIfWholeNumber; |
| |
| // There's no hope to be 1-precise outside this region. (Although problems can occur even inside it...) |
| if (doubleN > MAX_DOUBLE_OR_LONG || doubleN < MIN_DOUBLE_OR_LONG) break checkIfWholeNumber; |
| |
| long longN = num.longValue(); |
| double diff = doubleN - longN; |
| boolean exact; // We will try to ignore precision glitches (like 0.3 - 0.2 - 0.1 = -2.7E-17) |
| if (diff == 0) { |
| exact = true; |
| } else if (diff > 0) { |
| if (diff < LOWEST_ABOVE_ZERO) { |
| exact = false; |
| } else if (diff > HIGHEST_BELOW_ONE) { |
| exact = false; |
| longN++; |
| } else { |
| break checkIfWholeNumber; |
| } |
| } else { // => diff < 0 |
| if (diff > -LOWEST_ABOVE_ZERO) { |
| exact = false; |
| } else if (diff < -HIGHEST_BELOW_ONE) { |
| exact = false; |
| longN--; |
| } else { |
| break checkIfWholeNumber; |
| } |
| } |
| |
| // If we reach this, it can be treated as a whole number. |
| |
| if ((typeFlags & TypeFlags.BYTE) != 0 |
| && longN <= Byte.MAX_VALUE && longN >= Byte.MIN_VALUE) { |
| return new DoubleOrByte((Double) num, (byte) longN); |
| } else if ((typeFlags & TypeFlags.SHORT) != 0 |
| && longN <= Short.MAX_VALUE && longN >= Short.MIN_VALUE) { |
| return new DoubleOrShort((Double) num, (short) longN); |
| } else if ((typeFlags & TypeFlags.INTEGER) != 0 |
| && longN <= Integer.MAX_VALUE && longN >= Integer.MIN_VALUE) { |
| final int intN = (int) longN; |
| return (typeFlags & TypeFlags.FLOAT) != 0 && intN >= MIN_FLOAT_OR_INT && intN <= MAX_FLOAT_OR_INT |
| ? new DoubleOrIntegerOrFloat((Double) num, intN) |
| : new DoubleOrInteger((Double) num, intN); |
| } else if ((typeFlags & TypeFlags.LONG) != 0) { |
| if (exact) { |
| return new DoubleOrLong((Double) num, longN); |
| } else { |
| // We don't deal with non-exact numbers outside the range of int, as we already reach |
| // ULP 2.384185791015625E-7 there. |
| if (longN >= Integer.MIN_VALUE && longN <= Integer.MAX_VALUE) { |
| return new DoubleOrLong((Double) num, longN); |
| } else { |
| break checkIfWholeNumber; |
| } |
| } |
| } |
| // This point is reached if the double value was out of the range of target integer type(s). |
| // Falls through! |
| } while (false); |
| // If we reach this that means that it can't be treated as a whole number. |
| |
| if ((typeFlags & TypeFlags.FLOAT) != 0 && doubleN >= -Float.MAX_VALUE && doubleN <= Float.MAX_VALUE) { |
| return new DoubleOrFloat((Double) num); |
| } else { |
| // Simply Double: |
| return num; |
| } |
| } else if (numClass == Float.class) { |
| final float floatN = num.floatValue(); |
| |
| // Can we store it in an integer type? |
| checkIfWholeNumber: do { |
| if ((typeFlags & TypeFlags.MASK_KNOWN_INTEGERS) == 0) break checkIfWholeNumber; |
| |
| // There's no hope to be 1-precise outside this region. (Although problems can occur even inside it...) |
| if (floatN > MAX_FLOAT_OR_INT || floatN < MIN_FLOAT_OR_INT) break checkIfWholeNumber; |
| |
| int intN = num.intValue(); |
| double diff = floatN - intN; |
| boolean exact; // We will try to ignore precision glitches (like 0.3 - 0.2 - 0.1 = -2.7E-17) |
| if (diff == 0) { |
| exact = true; |
| // We already reach ULP 7.6293945E-6 with bytes, so we don't continue with shorts. |
| } else if (intN >= Byte.MIN_VALUE && intN <= Byte.MAX_VALUE) { |
| if (diff > 0) { |
| if (diff < 0.00001) { |
| exact = false; |
| } else if (diff > 0.99999) { |
| exact = false; |
| intN++; |
| } else { |
| break checkIfWholeNumber; |
| } |
| } else { // => diff < 0 |
| if (diff > -0.00001) { |
| exact = false; |
| } else if (diff < -0.99999) { |
| exact = false; |
| intN--; |
| } else { |
| break checkIfWholeNumber; |
| } |
| } |
| } else { |
| break checkIfWholeNumber; |
| } |
| |
| // If we reach this, it can be treated as a whole number. |
| |
| if ((typeFlags & TypeFlags.BYTE) != 0 && intN <= Byte.MAX_VALUE && intN >= Byte.MIN_VALUE) { |
| return new FloatOrByte((Float) num, (byte) intN); |
| } else if ((typeFlags & TypeFlags.SHORT) != 0 && intN <= Short.MAX_VALUE && intN >= Short.MIN_VALUE) { |
| return new FloatOrShort((Float) num, (short) intN); |
| } else if ((typeFlags & TypeFlags.INTEGER) != 0) { |
| return new FloatOrInteger((Float) num, intN); |
| } else if ((typeFlags & TypeFlags.LONG) != 0) { |
| // We can't even go outside the range of integers, so we don't need Long variation: |
| return exact |
| ? new FloatOrInteger((Float) num, intN) |
| : new FloatOrByte((Float) num, (byte) intN); // as !exact implies (-128..127) |
| } |
| // This point is reached if the float value was out of the range of target integer type(s). |
| // Falls through! |
| } while (false); |
| // If we reach this that means that it can't be treated as a whole number. So it's simply a Float: |
| return num; |
| } else if (numClass == Byte.class) { |
| return num; |
| } else if (numClass == Short.class) { |
| short pn = num.shortValue(); |
| if ((typeFlags & TypeFlags.BYTE) != 0 && pn <= Byte.MAX_VALUE && pn >= Byte.MIN_VALUE) { |
| return new ShortOrByte((Short) num, (byte) pn); |
| } else { |
| return num; |
| } |
| } else if (numClass == BigInteger.class) { |
| if ((typeFlags |
| & ((TypeFlags.MASK_KNOWN_INTEGERS | TypeFlags.MASK_KNOWN_NONINTEGERS) |
| ^ (TypeFlags.BIG_INTEGER | TypeFlags.BIG_DECIMAL))) != 0) { |
| BigInteger biNum = (BigInteger) num; |
| final int bitLength = biNum.bitLength(); // Doesn't include sign bit, so it's one less than expected |
| if ((typeFlags & TypeFlags.BYTE) != 0 && bitLength <= 7) { |
| return new BigIntegerOrByte(biNum); |
| } else if ((typeFlags & TypeFlags.SHORT) != 0 && bitLength <= 15) { |
| return new BigIntegerOrShort(biNum); |
| } else if ((typeFlags & TypeFlags.INTEGER) != 0 && bitLength <= 31) { |
| return new BigIntegerOrInteger(biNum); |
| } else if ((typeFlags & TypeFlags.LONG) != 0 && bitLength <= 63) { |
| return new BigIntegerOrLong(biNum); |
| } else if ((typeFlags & TypeFlags.FLOAT) != 0 |
| && (bitLength <= MAX_FLOAT_OR_INT_LOG_2 |
| || bitLength == MAX_FLOAT_OR_INT_LOG_2 + 1 |
| && biNum.getLowestSetBit() >= MAX_FLOAT_OR_INT_LOG_2)) { |
| return new BigIntegerOrFloat(biNum); |
| } else if ((typeFlags & TypeFlags.DOUBLE) != 0 |
| && (bitLength <= MAX_DOUBLE_OR_LONG_LOG_2 |
| || bitLength == MAX_DOUBLE_OR_LONG_LOG_2 + 1 |
| && biNum.getLowestSetBit() >= MAX_DOUBLE_OR_LONG_LOG_2)) { |
| return new BigIntegerOrDouble(biNum); |
| } else { |
| return num; |
| } |
| } else { |
| // No relevant coercion target types; return the BigInteger as is: |
| return num; |
| } |
| } else { |
| // Unknown number type: |
| return num; |
| } |
| } |
| |
| static interface ByteSource { Byte byteValue(); } |
| static interface ShortSource { Short shortValue(); } |
| static interface IntegerSource { Integer integerValue(); } |
| static interface LongSource { Long longValue(); } |
| static interface FloatSource { Float floatValue(); } |
| static interface DoubleSource { Double doubleValue(); } |
| static interface BigIntegerSource { BigInteger bigIntegerValue(); } |
| static interface BigDecimalSource { BigDecimal bigDecimalValue(); } |
| |
| /** |
| * Superclass of "Or"-ed numerical types. With an example, a {@code int} 1 has the fallback type {@code byte}, as |
| * that's the smallest type that can store the value, so it can be represented as an {@link IntegerOrByte}. |
| * This is useful as overloaded method selection only examines the type of the arguments, not the value of them, |
| * but with "Or"-ed types we can encode this value-related information into the argument type, hence influencing the |
| * method selection. |
| */ |
| abstract static class NumberWithFallbackType extends Number implements Comparable { |
| |
| protected abstract Number getSourceNumber(); |
| |
| @Override |
| public int intValue() { |
| return getSourceNumber().intValue(); |
| } |
| |
| @Override |
| public long longValue() { |
| return getSourceNumber().longValue(); |
| } |
| |
| @Override |
| public float floatValue() { |
| return getSourceNumber().floatValue(); |
| } |
| |
| @Override |
| public double doubleValue() { |
| return getSourceNumber().doubleValue(); |
| } |
| |
| @Override |
| public byte byteValue() { |
| return getSourceNumber().byteValue(); |
| } |
| |
| @Override |
| public short shortValue() { |
| return getSourceNumber().shortValue(); |
| } |
| |
| @Override |
| public int hashCode() { |
| return getSourceNumber().hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj != null && this.getClass() == obj.getClass()) { |
| return getSourceNumber().equals(((NumberWithFallbackType) obj).getSourceNumber()); |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return getSourceNumber().toString(); |
| } |
| |
| // We have to implement this, so that if a potential matching method expects a Comparable, which is implemented |
| // by all the supported numerical types, the "Or" type will be a match. |
| public int compareTo(Object o) { |
| Number n = getSourceNumber(); |
| if (n instanceof Comparable) { |
| return ((Comparable) n).compareTo(o); |
| } else { |
| throw new ClassCastException(n.getClass().getName() + " is not Comparable."); |
| } |
| } |
| |
| } |
| |
| /** |
| * Holds a {@link BigDecimal} that stores a whole number. When selecting a overloaded method, FreeMarker tries to |
| * associate {@link BigDecimal} values to parameters of types that can hold non-whole numbers, unless the |
| * {@link BigDecimal} is wrapped into this class, in which case it does the opposite. This mechanism is, however, |
| * too rough to prevent roll overs or magnitude losses. Those are not yet handled for backward compatibility (they |
| * were suppressed earlier too). |
| */ |
| static final class IntegerBigDecimal extends NumberWithFallbackType { |
| |
| private final BigDecimal n; |
| |
| IntegerBigDecimal(BigDecimal n) { |
| this.n = n; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| public BigInteger bigIntegerValue() { |
| return n.toBigInteger(); |
| } |
| |
| } |
| |
| static abstract class LongOrSmallerInteger extends NumberWithFallbackType { |
| |
| private final Long n; |
| |
| protected LongOrSmallerInteger(Long n) { |
| this.n = n; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| @Override |
| public long longValue() { |
| return n.longValue(); |
| } |
| |
| } |
| |
| static class LongOrByte extends LongOrSmallerInteger { |
| |
| private final byte w; |
| |
| LongOrByte(Long n, byte w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public byte byteValue() { |
| return w; |
| } |
| |
| } |
| |
| static class LongOrShort extends LongOrSmallerInteger { |
| |
| private final short w; |
| |
| LongOrShort(Long n, short w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public short shortValue() { |
| return w; |
| } |
| |
| } |
| |
| static class LongOrInteger extends LongOrSmallerInteger { |
| |
| private final int w; |
| |
| LongOrInteger(Long n, int w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| } |
| |
| static abstract class IntegerOrSmallerInteger extends NumberWithFallbackType { |
| |
| private final Integer n; |
| |
| protected IntegerOrSmallerInteger(Integer n) { |
| this.n = n; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| @Override |
| public int intValue() { |
| return n.intValue(); |
| } |
| |
| } |
| |
| static class IntegerOrByte extends IntegerOrSmallerInteger { |
| |
| private final byte w; |
| |
| IntegerOrByte(Integer n, byte w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public byte byteValue() { |
| return w; |
| } |
| |
| } |
| |
| static class IntegerOrShort extends IntegerOrSmallerInteger { |
| |
| private final short w; |
| |
| IntegerOrShort(Integer n, short w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public short shortValue() { |
| return w; |
| } |
| |
| } |
| |
| static class ShortOrByte extends NumberWithFallbackType { |
| |
| private final Short n; |
| private final byte w; |
| |
| protected ShortOrByte(Short n, byte w) { |
| this.n = n; |
| this.w = w; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| @Override |
| public short shortValue() { |
| return n.shortValue(); |
| } |
| |
| @Override |
| public byte byteValue() { |
| return w; |
| } |
| |
| } |
| |
| static abstract class DoubleOrWholeNumber extends NumberWithFallbackType { |
| |
| private final Double n; |
| |
| protected DoubleOrWholeNumber(Double n) { |
| this.n = n; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| @Override |
| public double doubleValue() { |
| return n.doubleValue(); |
| } |
| |
| } |
| |
| static final class DoubleOrByte extends DoubleOrWholeNumber { |
| |
| private final byte w; |
| |
| DoubleOrByte(Double n, byte w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public byte byteValue() { |
| return w; |
| } |
| |
| @Override |
| public short shortValue() { |
| return w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class DoubleOrShort extends DoubleOrWholeNumber { |
| |
| private final short w; |
| |
| DoubleOrShort(Double n, short w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public short shortValue() { |
| return w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class DoubleOrIntegerOrFloat extends DoubleOrWholeNumber { |
| |
| private final int w; |
| |
| DoubleOrIntegerOrFloat(Double n, int w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class DoubleOrInteger extends DoubleOrWholeNumber { |
| |
| private final int w; |
| |
| DoubleOrInteger(Double n, int w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class DoubleOrLong extends DoubleOrWholeNumber { |
| |
| private final long w; |
| |
| DoubleOrLong(Double n, long w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class DoubleOrFloat extends NumberWithFallbackType { |
| |
| private final Double n; |
| |
| DoubleOrFloat(Double n) { |
| this.n = n; |
| } |
| |
| @Override |
| public float floatValue() { |
| return n.floatValue(); |
| } |
| |
| @Override |
| public double doubleValue() { |
| return n.doubleValue(); |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| } |
| |
| static abstract class FloatOrWholeNumber extends NumberWithFallbackType { |
| |
| private final Float n; |
| |
| FloatOrWholeNumber(Float n) { |
| this.n = n; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| @Override |
| public float floatValue() { |
| return n.floatValue(); |
| } |
| |
| } |
| |
| static final class FloatOrByte extends FloatOrWholeNumber { |
| |
| private final byte w; |
| |
| FloatOrByte(Float n, byte w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public byte byteValue() { |
| return w; |
| } |
| |
| @Override |
| public short shortValue() { |
| return w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class FloatOrShort extends FloatOrWholeNumber { |
| |
| private final short w; |
| |
| FloatOrShort(Float n, short w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public short shortValue() { |
| return w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| static final class FloatOrInteger extends FloatOrWholeNumber { |
| |
| private final int w; |
| |
| FloatOrInteger(Float n, int w) { |
| super(n); |
| this.w = w; |
| } |
| |
| @Override |
| public int intValue() { |
| return w; |
| } |
| |
| @Override |
| public long longValue() { |
| return w; |
| } |
| |
| } |
| |
| abstract static class BigIntegerOrPrimitive extends NumberWithFallbackType { |
| |
| protected final BigInteger n; |
| |
| BigIntegerOrPrimitive(BigInteger n) { |
| this.n = n; |
| } |
| |
| @Override |
| protected Number getSourceNumber() { |
| return n; |
| } |
| |
| } |
| |
| final static class BigIntegerOrByte extends BigIntegerOrPrimitive { |
| |
| BigIntegerOrByte(BigInteger n) { |
| super(n); |
| } |
| |
| } |
| |
| final static class BigIntegerOrShort extends BigIntegerOrPrimitive { |
| |
| BigIntegerOrShort(BigInteger n) { |
| super(n); |
| } |
| |
| } |
| |
| final static class BigIntegerOrInteger extends BigIntegerOrPrimitive { |
| |
| BigIntegerOrInteger(BigInteger n) { |
| super(n); |
| } |
| |
| } |
| |
| final static class BigIntegerOrLong extends BigIntegerOrPrimitive { |
| |
| BigIntegerOrLong(BigInteger n) { |
| super(n); |
| } |
| |
| } |
| |
| abstract static class BigIntegerOrFPPrimitive extends BigIntegerOrPrimitive { |
| |
| BigIntegerOrFPPrimitive(BigInteger n) { |
| super(n); |
| } |
| |
| /** Faster version of {@link BigDecimal#floatValue()}, utilizes that the number known to fit into a long. */ |
| @Override |
| public float floatValue() { |
| return n.longValue(); |
| } |
| |
| /** Faster version of {@link BigDecimal#doubleValue()}, utilizes that the number known to fit into a long. */ |
| @Override |
| public double doubleValue() { |
| return n.longValue(); |
| } |
| |
| } |
| |
| final static class BigIntegerOrFloat extends BigIntegerOrFPPrimitive { |
| |
| BigIntegerOrFloat(BigInteger n) { |
| super(n); |
| } |
| |
| } |
| |
| final static class BigIntegerOrDouble extends BigIntegerOrFPPrimitive { |
| |
| BigIntegerOrDouble(BigInteger n) { |
| super(n); |
| } |
| |
| } |
| |
| /** |
| * Returns a non-negative number that indicates how much we want to avoid a given numerical type conversion. Since |
| * we only consider the types here, not the actual value, we always consider the worst case scenario. Like it will |
| * say that converting int to short is not allowed, although int 1 can be converted to byte without loss. To account |
| * for such situations, "Or"-ed types, like {@link IntegerOrByte} has to be used. |
| * |
| * @param fromC the non-primitive type of the argument (with other words, the actual type). |
| * Must be {@link Number} or its subclass. This is possibly an {@link NumberWithFallbackType} subclass. |
| * @param toC the <em>non-primitive</em> type of the target parameter (with other words, the format type). |
| * Must be a {@link Number} subclass, not {@link Number} itself. |
| * Must <em>not</em> be {@link NumberWithFallbackType} or its subclass. |
| * |
| * @return |
| * <p>The possible values are: |
| * <ul> |
| * <li>0: No conversion is needed |
| * <li>[0, 30000): Lossless conversion |
| * <li>[30000, 40000): Smaller precision loss in mantissa is possible. |
| * <li>[40000, 50000): Bigger precision loss in mantissa is possible. |
| * <li>{@link Integer#MAX_VALUE}: Conversion not allowed due to the possibility of magnitude loss or |
| * overflow</li> |
| * </ul> |
| * |
| * <p>At some places, we only care if the conversion is possible, i.e., whether the return value is |
| * {@link Integer#MAX_VALUE} or not. But when multiple overloaded methods have an argument type to which we |
| * could convert to, this number will influence which of those will be chosen. |
| */ |
| static int getArgumentConversionPrice(Class fromC, Class toC) { |
| // DO NOT EDIT, generated code! |
| // See: src\main\misc\overloadedNumberRules\README.txt |
| if (toC == fromC) { |
| return 0; |
| } else if (toC == Integer.class) { |
| if (fromC == IntegerBigDecimal.class) return 31003; |
| else if (fromC == BigDecimal.class) return 41003; |
| else if (fromC == Long.class) return Integer.MAX_VALUE; |
| else if (fromC == Double.class) return Integer.MAX_VALUE; |
| else if (fromC == Float.class) return Integer.MAX_VALUE; |
| else if (fromC == Byte.class) return 10003; |
| else if (fromC == BigInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrInteger.class) return 21003; |
| else if (fromC == DoubleOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return 22003; |
| else if (fromC == DoubleOrInteger.class) return 22003; |
| else if (fromC == DoubleOrLong.class) return Integer.MAX_VALUE; |
| else if (fromC == IntegerOrByte.class) return 0; |
| else if (fromC == DoubleOrByte.class) return 22003; |
| else if (fromC == LongOrByte.class) return 21003; |
| else if (fromC == Short.class) return 10003; |
| else if (fromC == LongOrShort.class) return 21003; |
| else if (fromC == ShortOrByte.class) return 10003; |
| else if (fromC == FloatOrInteger.class) return 21003; |
| else if (fromC == FloatOrByte.class) return 21003; |
| else if (fromC == FloatOrShort.class) return 21003; |
| else if (fromC == BigIntegerOrInteger.class) return 16003; |
| else if (fromC == BigIntegerOrLong.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrDouble.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrByte.class) return 16003; |
| else if (fromC == IntegerOrShort.class) return 0; |
| else if (fromC == DoubleOrShort.class) return 22003; |
| else if (fromC == BigIntegerOrShort.class) return 16003; |
| else return Integer.MAX_VALUE; |
| } else if (toC == Long.class) { |
| if (fromC == Integer.class) return 10004; |
| else if (fromC == IntegerBigDecimal.class) return 31004; |
| else if (fromC == BigDecimal.class) return 41004; |
| else if (fromC == Double.class) return Integer.MAX_VALUE; |
| else if (fromC == Float.class) return Integer.MAX_VALUE; |
| else if (fromC == Byte.class) return 10004; |
| else if (fromC == BigInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrInteger.class) return 0; |
| else if (fromC == DoubleOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return 21004; |
| else if (fromC == DoubleOrInteger.class) return 21004; |
| else if (fromC == DoubleOrLong.class) return 21004; |
| else if (fromC == IntegerOrByte.class) return 10004; |
| else if (fromC == DoubleOrByte.class) return 21004; |
| else if (fromC == LongOrByte.class) return 0; |
| else if (fromC == Short.class) return 10004; |
| else if (fromC == LongOrShort.class) return 0; |
| else if (fromC == ShortOrByte.class) return 10004; |
| else if (fromC == FloatOrInteger.class) return 21004; |
| else if (fromC == FloatOrByte.class) return 21004; |
| else if (fromC == FloatOrShort.class) return 21004; |
| else if (fromC == BigIntegerOrInteger.class) return 15004; |
| else if (fromC == BigIntegerOrLong.class) return 15004; |
| else if (fromC == BigIntegerOrDouble.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrByte.class) return 15004; |
| else if (fromC == IntegerOrShort.class) return 10004; |
| else if (fromC == DoubleOrShort.class) return 21004; |
| else if (fromC == BigIntegerOrShort.class) return 15004; |
| else return Integer.MAX_VALUE; |
| } else if (toC == Double.class) { |
| if (fromC == Integer.class) return 20007; |
| else if (fromC == IntegerBigDecimal.class) return 32007; |
| else if (fromC == BigDecimal.class) return 32007; |
| else if (fromC == Long.class) return 30007; |
| else if (fromC == Float.class) return 10007; |
| else if (fromC == Byte.class) return 20007; |
| else if (fromC == BigInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrInteger.class) return 21007; |
| else if (fromC == DoubleOrFloat.class) return 0; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return 0; |
| else if (fromC == DoubleOrInteger.class) return 0; |
| else if (fromC == DoubleOrLong.class) return 0; |
| else if (fromC == IntegerOrByte.class) return 20007; |
| else if (fromC == DoubleOrByte.class) return 0; |
| else if (fromC == LongOrByte.class) return 21007; |
| else if (fromC == Short.class) return 20007; |
| else if (fromC == LongOrShort.class) return 21007; |
| else if (fromC == ShortOrByte.class) return 20007; |
| else if (fromC == FloatOrInteger.class) return 10007; |
| else if (fromC == FloatOrByte.class) return 10007; |
| else if (fromC == FloatOrShort.class) return 10007; |
| else if (fromC == BigIntegerOrInteger.class) return 20007; |
| else if (fromC == BigIntegerOrLong.class) return 30007; |
| else if (fromC == BigIntegerOrDouble.class) return 20007; |
| else if (fromC == BigIntegerOrFloat.class) return 20007; |
| else if (fromC == BigIntegerOrByte.class) return 20007; |
| else if (fromC == IntegerOrShort.class) return 20007; |
| else if (fromC == DoubleOrShort.class) return 0; |
| else if (fromC == BigIntegerOrShort.class) return 20007; |
| else return Integer.MAX_VALUE; |
| } else if (toC == Float.class) { |
| if (fromC == Integer.class) return 30006; |
| else if (fromC == IntegerBigDecimal.class) return 33006; |
| else if (fromC == BigDecimal.class) return 33006; |
| else if (fromC == Long.class) return 40006; |
| else if (fromC == Double.class) return Integer.MAX_VALUE; |
| else if (fromC == Byte.class) return 20006; |
| else if (fromC == BigInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrInteger.class) return 30006; |
| else if (fromC == DoubleOrFloat.class) return 30006; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return 23006; |
| else if (fromC == DoubleOrInteger.class) return 30006; |
| else if (fromC == DoubleOrLong.class) return 40006; |
| else if (fromC == IntegerOrByte.class) return 24006; |
| else if (fromC == DoubleOrByte.class) return 23006; |
| else if (fromC == LongOrByte.class) return 24006; |
| else if (fromC == Short.class) return 20006; |
| else if (fromC == LongOrShort.class) return 24006; |
| else if (fromC == ShortOrByte.class) return 20006; |
| else if (fromC == FloatOrInteger.class) return 0; |
| else if (fromC == FloatOrByte.class) return 0; |
| else if (fromC == FloatOrShort.class) return 0; |
| else if (fromC == BigIntegerOrInteger.class) return 30006; |
| else if (fromC == BigIntegerOrLong.class) return 40006; |
| else if (fromC == BigIntegerOrDouble.class) return 40006; |
| else if (fromC == BigIntegerOrFloat.class) return 24006; |
| else if (fromC == BigIntegerOrByte.class) return 24006; |
| else if (fromC == IntegerOrShort.class) return 24006; |
| else if (fromC == DoubleOrShort.class) return 23006; |
| else if (fromC == BigIntegerOrShort.class) return 24006; |
| else return Integer.MAX_VALUE; |
| } else if (toC == Byte.class) { |
| if (fromC == Integer.class) return Integer.MAX_VALUE; |
| else if (fromC == IntegerBigDecimal.class) return 35001; |
| else if (fromC == BigDecimal.class) return 45001; |
| else if (fromC == Long.class) return Integer.MAX_VALUE; |
| else if (fromC == Double.class) return Integer.MAX_VALUE; |
| else if (fromC == Float.class) return Integer.MAX_VALUE; |
| else if (fromC == BigInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrLong.class) return Integer.MAX_VALUE; |
| else if (fromC == IntegerOrByte.class) return 22001; |
| else if (fromC == DoubleOrByte.class) return 25001; |
| else if (fromC == LongOrByte.class) return 23001; |
| else if (fromC == Short.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrShort.class) return Integer.MAX_VALUE; |
| else if (fromC == ShortOrByte.class) return 21001; |
| else if (fromC == FloatOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == FloatOrByte.class) return 23001; |
| else if (fromC == FloatOrShort.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrLong.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrDouble.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrByte.class) return 18001; |
| else if (fromC == IntegerOrShort.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrShort.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrShort.class) return Integer.MAX_VALUE; |
| else return Integer.MAX_VALUE; |
| } else if (toC == Short.class) { |
| if (fromC == Integer.class) return Integer.MAX_VALUE; |
| else if (fromC == IntegerBigDecimal.class) return 34002; |
| else if (fromC == BigDecimal.class) return 44002; |
| else if (fromC == Long.class) return Integer.MAX_VALUE; |
| else if (fromC == Double.class) return Integer.MAX_VALUE; |
| else if (fromC == Float.class) return Integer.MAX_VALUE; |
| else if (fromC == Byte.class) return 10002; |
| else if (fromC == BigInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == LongOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrLong.class) return Integer.MAX_VALUE; |
| else if (fromC == IntegerOrByte.class) return 21002; |
| else if (fromC == DoubleOrByte.class) return 24002; |
| else if (fromC == LongOrByte.class) return 22002; |
| else if (fromC == LongOrShort.class) return 22002; |
| else if (fromC == ShortOrByte.class) return 0; |
| else if (fromC == FloatOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == FloatOrByte.class) return 22002; |
| else if (fromC == FloatOrShort.class) return 22002; |
| else if (fromC == BigIntegerOrInteger.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrLong.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrDouble.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == BigIntegerOrByte.class) return 17002; |
| else if (fromC == IntegerOrShort.class) return 21002; |
| else if (fromC == DoubleOrShort.class) return 24002; |
| else if (fromC == BigIntegerOrShort.class) return 17002; |
| else return Integer.MAX_VALUE; |
| } else if (toC == BigDecimal.class) { |
| if (fromC == Integer.class) return 20008; |
| else if (fromC == IntegerBigDecimal.class) return 0; |
| else if (fromC == Long.class) return 20008; |
| else if (fromC == Double.class) return 20008; |
| else if (fromC == Float.class) return 20008; |
| else if (fromC == Byte.class) return 20008; |
| else if (fromC == BigInteger.class) return 10008; |
| else if (fromC == LongOrInteger.class) return 20008; |
| else if (fromC == DoubleOrFloat.class) return 20008; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return 20008; |
| else if (fromC == DoubleOrInteger.class) return 20008; |
| else if (fromC == DoubleOrLong.class) return 20008; |
| else if (fromC == IntegerOrByte.class) return 20008; |
| else if (fromC == DoubleOrByte.class) return 20008; |
| else if (fromC == LongOrByte.class) return 20008; |
| else if (fromC == Short.class) return 20008; |
| else if (fromC == LongOrShort.class) return 20008; |
| else if (fromC == ShortOrByte.class) return 20008; |
| else if (fromC == FloatOrInteger.class) return 20008; |
| else if (fromC == FloatOrByte.class) return 20008; |
| else if (fromC == FloatOrShort.class) return 20008; |
| else if (fromC == BigIntegerOrInteger.class) return 10008; |
| else if (fromC == BigIntegerOrLong.class) return 10008; |
| else if (fromC == BigIntegerOrDouble.class) return 10008; |
| else if (fromC == BigIntegerOrFloat.class) return 10008; |
| else if (fromC == BigIntegerOrByte.class) return 10008; |
| else if (fromC == IntegerOrShort.class) return 20008; |
| else if (fromC == DoubleOrShort.class) return 20008; |
| else if (fromC == BigIntegerOrShort.class) return 10008; |
| else return Integer.MAX_VALUE; |
| } else if (toC == BigInteger.class) { |
| if (fromC == Integer.class) return 10005; |
| else if (fromC == IntegerBigDecimal.class) return 10005; |
| else if (fromC == BigDecimal.class) return 40005; |
| else if (fromC == Long.class) return 10005; |
| else if (fromC == Double.class) return Integer.MAX_VALUE; |
| else if (fromC == Float.class) return Integer.MAX_VALUE; |
| else if (fromC == Byte.class) return 10005; |
| else if (fromC == LongOrInteger.class) return 10005; |
| else if (fromC == DoubleOrFloat.class) return Integer.MAX_VALUE; |
| else if (fromC == DoubleOrIntegerOrFloat.class) return 21005; |
| else if (fromC == DoubleOrInteger.class) return 21005; |
| else if (fromC == DoubleOrLong.class) return 21005; |
| else if (fromC == IntegerOrByte.class) return 10005; |
| else if (fromC == DoubleOrByte.class) return 21005; |
| else if (fromC == LongOrByte.class) return 10005; |
| else if (fromC == Short.class) return 10005; |
| else if (fromC == LongOrShort.class) return 10005; |
| else if (fromC == ShortOrByte.class) return 10005; |
| else if (fromC == FloatOrInteger.class) return 25005; |
| else if (fromC == FloatOrByte.class) return 25005; |
| else if (fromC == FloatOrShort.class) return 25005; |
| else if (fromC == BigIntegerOrInteger.class) return 0; |
| else if (fromC == BigIntegerOrLong.class) return 0; |
| else if (fromC == BigIntegerOrDouble.class) return 0; |
| else if (fromC == BigIntegerOrFloat.class) return 0; |
| else if (fromC == BigIntegerOrByte.class) return 0; |
| else if (fromC == IntegerOrShort.class) return 10005; |
| else if (fromC == DoubleOrShort.class) return 21005; |
| else if (fromC == BigIntegerOrShort.class) return 0; |
| else return Integer.MAX_VALUE; |
| } else { |
| // Unknown toC; we don't know how to convert to it: |
| return Integer.MAX_VALUE; |
| } |
| } |
| |
| static int compareNumberTypeSpecificity(Class c1, Class c2) { |
| // DO NOT EDIT, generated code! |
| // See: src\main\misc\overloadedNumberRules\README.txt |
| c1 = ClassUtil.primitiveClassToBoxingClass(c1); |
| c2 = ClassUtil.primitiveClassToBoxingClass(c2); |
| |
| if (c1 == c2) return 0; |
| |
| if (c1 == Integer.class) { |
| if (c2 == Long.class) return 4 - 3; |
| if (c2 == Double.class) return 7 - 3; |
| if (c2 == Float.class) return 6 - 3; |
| if (c2 == Byte.class) return 1 - 3; |
| if (c2 == Short.class) return 2 - 3; |
| if (c2 == BigDecimal.class) return 8 - 3; |
| if (c2 == BigInteger.class) return 5 - 3; |
| return 0; |
| } |
| if (c1 == Long.class) { |
| if (c2 == Integer.class) return 3 - 4; |
| if (c2 == Double.class) return 7 - 4; |
| if (c2 == Float.class) return 6 - 4; |
| if (c2 == Byte.class) return 1 - 4; |
| if (c2 == Short.class) return 2 - 4; |
| if (c2 == BigDecimal.class) return 8 - 4; |
| if (c2 == BigInteger.class) return 5 - 4; |
| return 0; |
| } |
| if (c1 == Double.class) { |
| if (c2 == Integer.class) return 3 - 7; |
| if (c2 == Long.class) return 4 - 7; |
| if (c2 == Float.class) return 6 - 7; |
| if (c2 == Byte.class) return 1 - 7; |
| if (c2 == Short.class) return 2 - 7; |
| if (c2 == BigDecimal.class) return 8 - 7; |
| if (c2 == BigInteger.class) return 5 - 7; |
| return 0; |
| } |
| if (c1 == Float.class) { |
| if (c2 == Integer.class) return 3 - 6; |
| if (c2 == Long.class) return 4 - 6; |
| if (c2 == Double.class) return 7 - 6; |
| if (c2 == Byte.class) return 1 - 6; |
| if (c2 == Short.class) return 2 - 6; |
| if (c2 == BigDecimal.class) return 8 - 6; |
| if (c2 == BigInteger.class) return 5 - 6; |
| return 0; |
| } |
| if (c1 == Byte.class) { |
| if (c2 == Integer.class) return 3 - 1; |
| if (c2 == Long.class) return 4 - 1; |
| if (c2 == Double.class) return 7 - 1; |
| if (c2 == Float.class) return 6 - 1; |
| if (c2 == Short.class) return 2 - 1; |
| if (c2 == BigDecimal.class) return 8 - 1; |
| if (c2 == BigInteger.class) return 5 - 1; |
| return 0; |
| } |
| if (c1 == Short.class) { |
| if (c2 == Integer.class) return 3 - 2; |
| if (c2 == Long.class) return 4 - 2; |
| if (c2 == Double.class) return 7 - 2; |
| if (c2 == Float.class) return 6 - 2; |
| if (c2 == Byte.class) return 1 - 2; |
| if (c2 == BigDecimal.class) return 8 - 2; |
| if (c2 == BigInteger.class) return 5 - 2; |
| return 0; |
| } |
| if (c1 == BigDecimal.class) { |
| if (c2 == Integer.class) return 3 - 8; |
| if (c2 == Long.class) return 4 - 8; |
| if (c2 == Double.class) return 7 - 8; |
| if (c2 == Float.class) return 6 - 8; |
| if (c2 == Byte.class) return 1 - 8; |
| if (c2 == Short.class) return 2 - 8; |
| if (c2 == BigInteger.class) return 5 - 8; |
| return 0; |
| } |
| if (c1 == BigInteger.class) { |
| if (c2 == Integer.class) return 3 - 5; |
| if (c2 == Long.class) return 4 - 5; |
| if (c2 == Double.class) return 7 - 5; |
| if (c2 == Float.class) return 6 - 5; |
| if (c2 == Byte.class) return 1 - 5; |
| if (c2 == Short.class) return 2 - 5; |
| if (c2 == BigDecimal.class) return 8 - 5; |
| return 0; |
| } |
| return 0; |
| } |
| |
| } |