freemarker-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ddek...@apache.org
Subject [24/54] [partial] incubator-freemarker git commit: Top level package name change to org.apache.freemarker, and some of of the internal package structure changes. Other smaller cleanup. To be continued...
Date Thu, 16 Feb 2017 23:08:49 GMT
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/ext/beans/OverloadedMethodsSubset.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/OverloadedMethodsSubset.java b/src/main/java/freemarker/ext/beans/OverloadedMethodsSubset.java
deleted file mode 100644
index eeac0d0..0000000
--- a/src/main/java/freemarker/ext/beans/OverloadedMethodsSubset.java
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * 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.io.Serializable;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import freemarker.template.TemplateModelException;
-import freemarker.template.utility.ClassUtil;
-import freemarker.template.utility.NullArgumentException;
-
-/**
- * Encapsulates the rules and data structures (including cache) for choosing of the best matching callable member for
- * a parameter list, from a given set of callable members. There are two subclasses of this, one for non-varags methods,
- * and one for varargs methods.
- */
-abstract class OverloadedMethodsSubset {
-    
-    /** 
-     * Used for an optimization trick to substitute an array of whatever size that contains only 0-s. Since this array
-     * is 0 long, this means that the code that reads the int[] always have to check if the int[] has this value, and
-     * then it has to act like if was all 0-s.  
-     */
-    static final int[] ALL_ZEROS_ARRAY = new int[0];
-
-    private static final int[][] ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY = new int[1][];
-    static {
-        ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY[0] = ALL_ZEROS_ARRAY;
-    }
-
-    private Class[/*number of args*/][/*arg index*/] unwrappingHintsByParamCount;
-    
-    /**
-     * Tells what types occur at a given parameter position with a bit field. See {@link TypeFlags}.
-     */
-    private int[/*number of args*/][/*arg index*/] typeFlagsByParamCount;
-    
-    // TODO: This can cause memory-leak when classes are re-loaded. However, first the genericClassIntrospectionCache
-    // and such need to be fixed in this regard. 
-    private final Map/*<ArgumentTypes, MaybeEmptyCallableMemberDescriptor>*/ argTypesToMemberDescCache
-            = new ConcurrentHashMap(6, 0.75f, 1);
-    
-    private final List/*<ReflectionCallableMemberDescriptor>*/ memberDescs = new LinkedList();
-    
-    /** Enables 2.3.21 {@link BeansWrapper} incompatibleImprovements */
-    protected final boolean bugfixed;
-    
-    OverloadedMethodsSubset(boolean bugfixed) {
-        this.bugfixed = bugfixed;
-    }
-    
-    void addCallableMemberDescriptor(ReflectionCallableMemberDescriptor memberDesc) {
-        memberDescs.add(memberDesc);
-        
-        // Warning: Do not modify this array, or put it into unwrappingHintsByParamCount by reference, as the arrays
-        // inside that are modified!
-        final Class[] prepedParamTypes = preprocessParameterTypes(memberDesc);
-        final int paramCount = prepedParamTypes.length;  // Must be the same as the length of the original param list
-        
-        // Merge these unwrapping hints with the existing table of hints:
-        if (unwrappingHintsByParamCount == null) {
-            unwrappingHintsByParamCount = new Class[paramCount + 1][];
-            unwrappingHintsByParamCount[paramCount] = prepedParamTypes.clone();
-        } else if (unwrappingHintsByParamCount.length <= paramCount) {
-            Class[][] newUnwrappingHintsByParamCount = new Class[paramCount + 1][];
-            System.arraycopy(unwrappingHintsByParamCount, 0, newUnwrappingHintsByParamCount, 0,
-                    unwrappingHintsByParamCount.length);
-            unwrappingHintsByParamCount = newUnwrappingHintsByParamCount;
-            unwrappingHintsByParamCount[paramCount] = prepedParamTypes.clone();
-        } else {
-            Class[] unwrappingHints = unwrappingHintsByParamCount[paramCount]; 
-            if (unwrappingHints == null) {
-                unwrappingHintsByParamCount[paramCount] = prepedParamTypes.clone();
-            } else {
-                for (int paramIdx = 0; paramIdx < prepedParamTypes.length; paramIdx++) {
-                    // For each parameter list length, we merge the argument type arrays into a single Class[] that
-                    // stores the most specific common types for each position. Hence we will possibly use a too generic
-                    // hint for the unwrapping. For correct behavior, for each overloaded methods its own parameter
-                    // types should be used as a hint. But without unwrapping the arguments, we couldn't select the
-                    // overloaded method. So we had to unwrap with all possible target types of each parameter position,
-                    // which would be slow and its result would be uncacheable (as we don't have anything usable as
-                    // a lookup key). So we just use this compromise.
-                    unwrappingHints[paramIdx] = getCommonSupertypeForUnwrappingHint(
-                            unwrappingHints[paramIdx], prepedParamTypes[paramIdx]);
-                }
-            }
-        }
-
-        int[] typeFlagsByParamIdx = ALL_ZEROS_ARRAY;
-        if (bugfixed) {
-            // Fill typeFlagsByParamCount (if necessary)
-            for (int paramIdx = 0; paramIdx < paramCount; paramIdx++) {
-                final int typeFlags = TypeFlags.classToTypeFlags(prepedParamTypes[paramIdx]);
-                if (typeFlags != 0) {
-                    if (typeFlagsByParamIdx == ALL_ZEROS_ARRAY) {
-                        typeFlagsByParamIdx = new int[paramCount];
-                    }
-                    typeFlagsByParamIdx[paramIdx] = typeFlags;
-                }
-            }
-            mergeInTypesFlags(paramCount, typeFlagsByParamIdx);
-        }
-        
-        afterWideningUnwrappingHints(
-                bugfixed ? prepedParamTypes : unwrappingHintsByParamCount[paramCount],
-                typeFlagsByParamIdx);
-    }
-    
-    Class[][] getUnwrappingHintsByParamCount() {
-        return unwrappingHintsByParamCount;
-    }
-    
-    @SuppressFBWarnings(value="JLM_JSR166_UTILCONCURRENT_MONITORENTER",
-            justification="Locks for member descriptor creation only")
-    final MaybeEmptyCallableMemberDescriptor getMemberDescriptorForArgs(Object[] args, boolean varArg) {
-        ArgumentTypes argTypes = new ArgumentTypes(args, bugfixed);
-        MaybeEmptyCallableMemberDescriptor memberDesc
-                = (MaybeEmptyCallableMemberDescriptor) argTypesToMemberDescCache.get(argTypes);
-        if (memberDesc == null) {
-            // Synchronized so that we won't unnecessarily create the same member desc. for multiple times in parallel.
-            synchronized (argTypesToMemberDescCache) {
-                memberDesc = (MaybeEmptyCallableMemberDescriptor) argTypesToMemberDescCache.get(argTypes);
-                if (memberDesc == null) {
-                    memberDesc = argTypes.getMostSpecific(memberDescs, varArg);
-                    argTypesToMemberDescCache.put(argTypes, memberDesc);
-                }
-            }
-        }
-        return memberDesc;
-    }
-    
-    Iterator/*<ReflectionCallableMemberDescriptor>*/ getMemberDescriptors() {
-        return memberDescs.iterator();
-    }
-    
-    abstract Class[] preprocessParameterTypes(CallableMemberDescriptor memberDesc);
-    abstract void afterWideningUnwrappingHints(Class[] paramTypes, int[] paramNumericalTypes);
-    
-    abstract MaybeEmptyMemberAndArguments getMemberAndArguments(List/*<TemplateModel>*/ tmArgs, 
-            BeansWrapper unwrapper) throws TemplateModelException;
-
-    /**
-     * Returns the most specific common class (or interface) of two parameter types for the purpose of unwrapping.
-     * This is trickier than finding the most specific overlapping superclass of two classes, because:
-     * <ul>
-     *   <li>It considers primitive classes as the subclasses of the boxing classes.</li>
-     *   <li>If the only common class is {@link Object}, it will try to find a common interface. If there are more
-     *       of them, it will start removing those that are known to be uninteresting as unwrapping hints.</li>
-     * </ul>
-     * 
-     * @param c1 Parameter type 1
-     * @param c2 Parameter type 2
-     */
-    protected Class getCommonSupertypeForUnwrappingHint(Class c1, Class c2) {
-        if (c1 == c2) return c1;
-        // This also means that the hint for (Integer, Integer) will be Integer, not just Number. This is consistent
-        // with how non-overloaded method hints work.
-        
-        if (bugfixed) {
-            // c1 primitive class to boxing class:
-            final boolean c1WasPrim; 
-            if (c1.isPrimitive()) {
-                c1 = ClassUtil.primitiveClassToBoxingClass(c1);
-                c1WasPrim = true;
-            } else {
-                c1WasPrim = false;
-            }
-            
-            // c2 primitive class to boxing class:
-            final boolean c2WasPrim; 
-            if (c2.isPrimitive()) {
-                c2 = ClassUtil.primitiveClassToBoxingClass(c2);
-                c2WasPrim = true;
-            } else {
-                c2WasPrim = false;
-            }
-    
-            if (c1 == c2) {
-                // If it was like int and Integer, boolean and Boolean, etc., we return the boxing type (as that's the
-                // less specific, because it allows null.)
-                // (If it was two equivalent primitives, we don't get here, because of the 1st line of the method.) 
-                return c1;
-            } else if (Number.class.isAssignableFrom(c1) && Number.class.isAssignableFrom(c2)) {
-                // We don't want the unwrapper to convert to a numerical super-type [*] as it's not yet known what the
-                // actual number type of the chosen method will be. We will postpone the actual numerical conversion
-                // until that, especially as some conversions (like fixed point to floating point) can be lossy.
-                // * Numerical super-type: Like long > int > short > byte.  
-                return Number.class;
-            } else if (c1WasPrim || c2WasPrim) {
-                // At this point these all stand:
-                // - At least one of them was primitive
-                // - No more than one of them was numerical
-                // - They don't have the same wrapper (boxing) class
-                return Object.class;
-            }
-            // Falls through
-        } else {  // old buggy behavior
-            if (c2.isPrimitive()) {
-                if (c2 == Byte.TYPE) c2 = Byte.class;
-                else if (c2 == Short.TYPE) c2 = Short.class;
-                else if (c2 == Character.TYPE) c2 = Character.class;
-                else if (c2 == Integer.TYPE) c2 = Integer.class;
-                else if (c2 == Float.TYPE) c2 = Float.class;
-                else if (c2 == Long.TYPE) c2 = Long.class;
-                else if (c2 == Double.TYPE) c2 = Double.class;
-            }
-        }
-        
-        // We never get to this point if buxfixed is true and any of these stands:
-        // - One of classes was a primitive type
-        // - One of classes was a numerical type (either boxing type or primitive)
-        
-        Set commonTypes = _MethodUtil.getAssignables(c1, c2);
-        commonTypes.retainAll(_MethodUtil.getAssignables(c2, c1));
-        if (commonTypes.isEmpty()) {
-            // Can happen when at least one of the arguments is an interface, as
-            // they don't have Object at the root of their hierarchy
-            return Object.class;
-        }
-        
-        // Gather maximally specific elements. Yes, there can be more than one 
-        // thank to interfaces. I.e., if you call this method for String.class 
-        // and Number.class, you'll have Comparable, Serializable, and Object as 
-        // maximal elements. 
-        List max = new ArrayList();
-        listCommonTypes:  for (Iterator commonTypesIter = commonTypes.iterator(); commonTypesIter.hasNext(); ) {
-            Class clazz = (Class) commonTypesIter.next();
-            for (Iterator maxIter = max.iterator(); maxIter.hasNext(); ) {
-                Class maxClazz = (Class) maxIter.next();
-                if (_MethodUtil.isMoreOrSameSpecificParameterType(maxClazz, clazz, false /*bugfixed [1]*/, 0) != 0) {
-                    // clazz can't be maximal, if there's already a more specific or equal maximal than it.
-                    continue listCommonTypes;
-                }
-                if (_MethodUtil.isMoreOrSameSpecificParameterType(clazz, maxClazz, false /*bugfixed [1]*/, 0) != 0) {
-                    // If it's more specific than a currently maximal element,
-                    // that currently maximal is no longer a maximal.
-                    maxIter.remove();
-                }
-                // 1: We don't use bugfixed at the "[1]"-marked points because it's slower and doesn't make any
-                //    difference here as it's ensured that nor c1 nor c2 is primitive or numerical. The bugfix has only
-                //    affected the treatment of primitives and numerical types. 
-            }
-            // If we get here, no current maximal is more specific than the
-            // current class, so clazz is a new maximal so far.
-            max.add(clazz);
-        }
-        
-        if (max.size() > 1) {  // we have an ambiguity
-            if (bugfixed) {
-                // Find the non-interface class
-                for (Iterator it = max.iterator(); it.hasNext(); ) {
-                    Class maxCl = (Class) it.next();
-                    if (!maxCl.isInterface()) {
-                        if (maxCl != Object.class) {  // This actually shouldn't ever happen, but to be sure...
-                            // If it's not Object, we use it as the most specific
-                            return maxCl;
-                        } else {
-                            // Otherwise remove Object, and we will try with the interfaces 
-                            it.remove();
-                        }
-                    }
-                }
-                
-                // At this point we only have interfaces left.
-                // Try removing interfaces about which we know that they are useless as unwrapping hints:
-                max.remove(Cloneable.class);
-                if (max.size() > 1) {  // Still have an ambiguity...
-                    max.remove(Serializable.class);
-                    if (max.size() > 1) {  // Still had an ambiguity...
-                        max.remove(Comparable.class);
-                        if (max.size() > 1) {
-                            return Object.class; // Still had an ambiguity... no luck.
-                        }
-                    }
-                }
-            } else {
-                return Object.class;
-            }
-        }
-        
-        return (Class) max.get(0);
-    }
-    
-    /**
-     * Gets the "type flags" of each parameter positions, or {@code null} if there's no method with this parameter
-     * count or if we are in pre-2.3.21 mode, or {@link #ALL_ZEROS_ARRAY} if there were no parameters that turned
-     * on a flag. The returned {@code int}-s are one or more {@link TypeFlags} constants binary "or"-ed together.  
-     */
-    final protected int[] getTypeFlags(int paramCount) {
-        return typeFlagsByParamCount != null && typeFlagsByParamCount.length > paramCount
-                ? typeFlagsByParamCount[paramCount]
-                : null;
-    }
-
-    /**
-     * Updates the content of the {@link #typeFlagsByParamCount} field with the parameter type flags of a method.
-     * Don't call this when {@link #bugfixed} is {@code false}! 
-     * 
-     * @param dstParamCount The parameter count for which we want to merge in the type flags 
-     * @param srcTypeFlagsByParamIdx If shorter than {@code dstParamCount}, its last item will be repeated until
-     *        dstParamCount length is reached. If longer, the excessive items will be ignored.
-     *        Maybe {@link #ALL_ZEROS_ARRAY}. Maybe a 0-length array. Can't be {@code null}.
-     */
-    final protected void mergeInTypesFlags(int dstParamCount, int[] srcTypeFlagsByParamIdx) {
-        NullArgumentException.check("srcTypesFlagsByParamIdx", srcTypeFlagsByParamIdx);
-        
-        // Special case of 0 param count:
-        if (dstParamCount == 0) {
-            if (typeFlagsByParamCount == null) {
-                typeFlagsByParamCount = ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY;
-            } else if (typeFlagsByParamCount != ZERO_PARAM_COUNT_TYPE_FLAGS_ARRAY) {
-                typeFlagsByParamCount[0] = ALL_ZEROS_ARRAY;
-            }
-            return;
-        }
-        
-        // Ensure that typesFlagsByParamCount[dstParamCount] exists:
-        if (typeFlagsByParamCount == null) {
-            typeFlagsByParamCount = new int[dstParamCount + 1][];
-        } else if (typeFlagsByParamCount.length <= dstParamCount) {
-            int[][] newTypeFlagsByParamCount = new int[dstParamCount + 1][];
-            System.arraycopy(typeFlagsByParamCount, 0, newTypeFlagsByParamCount, 0,
-                    typeFlagsByParamCount.length);
-            typeFlagsByParamCount = newTypeFlagsByParamCount;
-        }
-        
-        int[] dstTypeFlagsByParamIdx = typeFlagsByParamCount[dstParamCount];
-        if (dstTypeFlagsByParamIdx == null) {
-            // This is the first method added with this number of params => no merging
-            
-            if (srcTypeFlagsByParamIdx != ALL_ZEROS_ARRAY) {
-                int srcParamCount = srcTypeFlagsByParamIdx.length;
-                dstTypeFlagsByParamIdx = new int[dstParamCount];
-                for (int paramIdx = 0; paramIdx < dstParamCount; paramIdx++) {
-                    dstTypeFlagsByParamIdx[paramIdx]
-                            = srcTypeFlagsByParamIdx[paramIdx < srcParamCount ? paramIdx : srcParamCount - 1];
-                }
-            } else {
-                dstTypeFlagsByParamIdx = ALL_ZEROS_ARRAY;
-            }
-            
-            typeFlagsByParamCount[dstParamCount] = dstTypeFlagsByParamIdx;
-        } else {
-            // dstTypeFlagsByParamIdx != null, so we need to merge into it.
-            
-            if (srcTypeFlagsByParamIdx == dstTypeFlagsByParamIdx) {
-                // Used to occur when both are ALL_ZEROS_ARRAY
-                return;
-            }
-            
-            // As we will write dstTypeFlagsByParamIdx, it can't remain ALL_ZEROS_ARRAY anymore. 
-            if (dstTypeFlagsByParamIdx == ALL_ZEROS_ARRAY && dstParamCount > 0) {
-                dstTypeFlagsByParamIdx = new int[dstParamCount];
-                typeFlagsByParamCount[dstParamCount] = dstTypeFlagsByParamIdx;
-            }
-            
-            for (int paramIdx = 0; paramIdx < dstParamCount; paramIdx++) {
-                final int srcParamTypeFlags;
-                if (srcTypeFlagsByParamIdx != ALL_ZEROS_ARRAY) {
-                    int srcParamCount = srcTypeFlagsByParamIdx.length;
-                    srcParamTypeFlags = srcTypeFlagsByParamIdx[paramIdx < srcParamCount ? paramIdx : srcParamCount - 1]; 
-                } else {
-                    srcParamTypeFlags = 0;
-                }
-                
-                final int dstParamTypesFlags = dstTypeFlagsByParamIdx[paramIdx];
-                if (dstParamTypesFlags != srcParamTypeFlags) {
-                    int mergedTypeFlags = dstParamTypesFlags | srcParamTypeFlags;
-                    if ((mergedTypeFlags & TypeFlags.MASK_ALL_NUMERICALS) != 0) {
-                        // Must not be set if we don't have numerical type at this index! 
-                        mergedTypeFlags |= TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT;
-                    }
-                    dstTypeFlagsByParamIdx[paramIdx] = mergedTypeFlags; 
-                }
-            }
-        }
-    }
-    
-    protected void forceNumberArgumentsToParameterTypes(
-            Object[] args, Class[] paramTypes, int[] typeFlagsByParamIndex) {
-        final int paramTypesLen = paramTypes.length;
-        final int argsLen = args.length;
-        for (int argIdx = 0; argIdx < argsLen; argIdx++) {
-            final int paramTypeIdx = argIdx < paramTypesLen ? argIdx : paramTypesLen - 1;
-            final int typeFlags = typeFlagsByParamIndex[paramTypeIdx];
-            
-            // Forcing the number type can only be interesting if there are numerical parameter types on that index,
-            // and the unwrapping was not to an exact numerical type.
-            if ((typeFlags & TypeFlags.WIDENED_NUMERICAL_UNWRAPPING_HINT) != 0) {
-                final Object arg = args[argIdx];
-                // If arg isn't a number, we can't do any conversions anyway, regardless of the param type.
-                if (arg instanceof Number) {
-                    final Class targetType = paramTypes[paramTypeIdx];
-                    final Number convertedArg = BeansWrapper.forceUnwrappedNumberToType(
-                            (Number) arg, targetType, bugfixed);
-                    if (convertedArg != null) {
-                        args[argIdx] = convertedArg;
-                    }
-                }
-            }
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/ext/beans/OverloadedNumberUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/beans/OverloadedNumberUtil.java b/src/main/java/freemarker/ext/beans/OverloadedNumberUtil.java
deleted file mode 100644
index 6b804fd..0000000
--- a/src/main/java/freemarker/ext/beans/OverloadedNumberUtil.java
+++ /dev/null
@@ -1,1288 +0,0 @@
-/*
- * 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;
-    }
-
-}


Mime
View raw message