_Private_ScalarConversions.java

/*
 * Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * or in the "license" file accompanying this file. This file 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 com.amazon.ion.impl;

import com.amazon.ion.Decimal;
import com.amazon.ion.IntegerSize;
import com.amazon.ion.IonException;
import com.amazon.ion.IonType;
import com.amazon.ion.Timestamp;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;

/**
 * NOT FOR APPLICATION USE!
 */
public class _Private_ScalarConversions
{
    public static final class AS_TYPE {

        public static final int null_value         =  1;
        public static final int boolean_value      =  2;
        public static final int int_value          =  3;
        public static final int long_value         =  4;
        public static final int bigInteger_value   =  5;
        public static final int decimal_value      =  6;
        public static final int double_value       =  7;
        public static final int string_value       =  8;
        public static final int date_value         =  9;
        public static final int timestamp_value    = 10;

        static final int idx_to_bit_mask(int idx) {
            return 1 << (idx - 1);
        }

        public static final int numeric_types      = idx_to_bit_mask(int_value)
                                                   | idx_to_bit_mask(long_value)
                                                   | idx_to_bit_mask(bigInteger_value)
                                                   | idx_to_bit_mask(decimal_value)
                                                   | idx_to_bit_mask(double_value);

        public static final int datetime_types     = idx_to_bit_mask(date_value)
                                                   | idx_to_bit_mask(timestamp_value);

        public static final int convertable_type   = idx_to_bit_mask(numeric_types)
                                                   | idx_to_bit_mask(datetime_types)
                                                   | idx_to_bit_mask(boolean_value)
                                                   | idx_to_bit_mask(string_value);
    }

    public static IntegerSize getIntegerSize(int authoritative_type) {
        switch (authoritative_type)
        {
            case AS_TYPE.int_value:
                return IntegerSize.INT;
            case AS_TYPE.long_value:
                return IntegerSize.LONG;
            case AS_TYPE.bigInteger_value:
                return IntegerSize.BIG_INTEGER;
            default:
                return null;
        }
    }

    public static String getValueTypeName(int value_type) {
        switch (value_type) {
        case AS_TYPE.null_value:       return "null";
        case AS_TYPE.boolean_value:    return "boolean";
        case AS_TYPE.int_value:        return "int";
        case AS_TYPE.long_value:       return "long";
        case AS_TYPE.bigInteger_value: return "bigInteger";
        case AS_TYPE.decimal_value:    return "decimal";
        case AS_TYPE.double_value:     return "double";
        case AS_TYPE.string_value:     return "string";
        case AS_TYPE.date_value:       return "date";
        case AS_TYPE.timestamp_value:  return "timestamp";
        default:                       return "<unrecognized conversion value type: "+Integer.toString(value_type)+">";
        }
    }
    public static String get_value_type_name(int value_type) {
        switch (value_type) {
        case AS_TYPE.null_value:
        case AS_TYPE.boolean_value:
        case AS_TYPE.int_value:
        case AS_TYPE.long_value:
        case AS_TYPE.bigInteger_value:
        case AS_TYPE.decimal_value:
        case AS_TYPE.double_value:
        case AS_TYPE.string_value:
        case AS_TYPE.date_value:
        case AS_TYPE.timestamp_value:
            return getValueTypeName(value_type)+"_value";
        default:
            return "<unrecognized conversion value type: "
                   +Integer.toString(value_type)
                   + ">";
        }
    }

    protected static int FNID_no_conversion               = -1;
    protected static int FNID_identity                    =  0;

    //from_string_conversion
    protected final static int FNID_FROM_STRING_TO_NULL         =  1;
    protected final static int FNID_FROM_STRING_TO_BOOLEAN      =  2;
    protected final static int FNID_FROM_STRING_TO_INT          =  3;
    protected final static int FNID_FROM_STRING_TO_LONG         =  4;
    protected final static int FNID_FROM_STRING_TO_BIGINTEGER   =  5;
    protected final static int FNID_FROM_STRING_TO_DECIMAL      =  6;
    protected final static int FNID_FROM_STRING_TO_DOUBLE       =  7;
    protected final static int FNID_FROM_STRING_TO_DATE         =  8;
    protected final static int FNID_FROM_STRING_TO_TIMESTAMP    =  9;
    static int [] from_string_conversion = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_FROM_STRING_TO_NULL,
                        FNID_FROM_STRING_TO_BOOLEAN,
                        FNID_FROM_STRING_TO_INT,
                        FNID_FROM_STRING_TO_LONG,
                        FNID_FROM_STRING_TO_BIGINTEGER,
                        FNID_FROM_STRING_TO_DECIMAL,
                        FNID_FROM_STRING_TO_DOUBLE,
                        FNID_identity,
                        FNID_FROM_STRING_TO_DATE,
                        FNID_FROM_STRING_TO_TIMESTAMP,
                        FNID_no_conversion,
                        FNID_no_conversion
                    };

    //to_string_conversions;
    protected final static int FNID_FROM_NULL_TO_STRING         = 10;
    protected final static int FNID_FROM_BOOLEAN_TO_STRING      = 11;
    protected final static int FNID_FROM_INT_TO_STRING          = 12;
    protected final static int FNID_FROM_LONG_TO_STRING         = 13;
    protected final static int FNID_FROM_BIGINTEGER_TO_STRING   = 14;
    protected final static int FNID_FROM_DECIMAL_TO_STRING      = 15;
    protected final static int FNID_FROM_DOUBLE_TO_STRING       = 16;
    protected final static int FNID_FROM_DATE_TO_STRING         = 17;
    protected final static int FNID_FROM_TIMESTAMP_TO_STRING    = 18;
    static int [] to_string_conversions = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_FROM_NULL_TO_STRING,
                        FNID_FROM_BOOLEAN_TO_STRING,
                        FNID_FROM_INT_TO_STRING,
                        FNID_FROM_LONG_TO_STRING,
                        FNID_FROM_BIGINTEGER_TO_STRING,
                        FNID_FROM_DECIMAL_TO_STRING,
                        FNID_FROM_DOUBLE_TO_STRING,
                        FNID_identity,
                        FNID_FROM_DATE_TO_STRING,
                        FNID_FROM_TIMESTAMP_TO_STRING,
                        FNID_no_conversion,
                        FNID_no_conversion
                    };


    //to_int_conversion;
    protected final static int FNID_FROM_LONG_TO_INT         = 19;
    protected final static int FNID_FROM_BIGINTEGER_TO_INT   = 20;
    protected final static int FNID_FROM_DECIMAL_TO_INT      = 21;
    protected final static int FNID_FROM_DOUBLE_TO_INT       = 22;
    static int [] to_int_conversion = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_identity,
                        FNID_FROM_LONG_TO_INT,
                        FNID_FROM_BIGINTEGER_TO_INT,
                        FNID_FROM_DECIMAL_TO_INT,
                        FNID_FROM_DOUBLE_TO_INT,
                        FNID_FROM_STRING_TO_INT,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion
                };

    //to_long_conversion;
    protected final static int FNID_FROM_INT_TO_LONG          = 23;
    protected final static int FNID_FROM_BIGINTEGER_TO_LONG   = 24;
    protected final static int FNID_FROM_DECIMAL_TO_LONG      = 25;
    protected final static int FNID_FROM_DOUBLE_TO_LONG       = 26;
    static int [] to_long_conversion = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_FROM_INT_TO_LONG,
                        FNID_identity,
                        FNID_FROM_BIGINTEGER_TO_LONG,
                        FNID_FROM_DECIMAL_TO_LONG,
                        FNID_FROM_DOUBLE_TO_LONG,
                        FNID_FROM_STRING_TO_LONG,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion
                    };


    //to_bigInteger_conversion;
    protected final static int FNID_FROM_INT_TO_BIGINTEGER          = 27;
    protected final static int FNID_FROM_LONG_TO_BIGINTEGER         = 28;
    protected final static int FNID_FROM_DECIMAL_TO_BIGINTEGER      = 29;
    protected final static int FNID_FROM_DOUBLE_TO_BIGINTEGER       = 30;
    static int [] to_bigInteger_conversion = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_FROM_INT_TO_BIGINTEGER,
                        FNID_FROM_LONG_TO_BIGINTEGER,
                        FNID_identity,
                        FNID_FROM_DECIMAL_TO_BIGINTEGER,
                        FNID_FROM_DOUBLE_TO_BIGINTEGER,
                        FNID_FROM_STRING_TO_BIGINTEGER,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion
                    };

    //to_decimal_conversion;
    protected final static int FNID_FROM_INT_TO_DECIMAL          = 31;
    protected final static int FNID_FROM_LONG_TO_DECIMAL         = 32;
    protected final static int FNID_FROM_BIGINTEGER_TO_DECIMAL   = 33;
    protected final static int FNID_FROM_DOUBLE_TO_DECIMAL       = 34;
    static int [] to_decimal_conversion = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_FROM_INT_TO_DECIMAL,
                        FNID_FROM_LONG_TO_DECIMAL,
                        FNID_FROM_BIGINTEGER_TO_DECIMAL,
                        FNID_identity,
                        FNID_FROM_DOUBLE_TO_DECIMAL,
                        FNID_FROM_STRING_TO_DECIMAL,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion
                    };

    //to_double_conversion;
    protected final static int FNID_FROM_INT_TO_DOUBLE          = 35;
    protected final static int FNID_FROM_LONG_TO_DOUBLE         = 36;
    protected final static int FNID_FROM_BIGINTEGER_TO_DOUBLE   = 37;
    protected final static int FNID_FROM_DECIMAL_TO_DOUBLE      = 38;
    static int [] to_double_conversion = {
                        FNID_no_conversion,  // fake entry to switch from 0 based to 1 based
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_FROM_INT_TO_DOUBLE,
                        FNID_FROM_LONG_TO_DOUBLE,
                        FNID_FROM_BIGINTEGER_TO_DOUBLE,
                        FNID_FROM_DECIMAL_TO_DOUBLE,
                        FNID_identity,
                        FNID_FROM_STRING_TO_DOUBLE,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion,
                        FNID_no_conversion
                    };
    protected final static int FNID_FROM_TIMESTAMP_TO_DATE      = 39;
    protected final static int FNID_FROM_DATE_TO_TIMESTAMP      = 40;

    public final static String getAllValueTypeNames(int value_type) {
        StringBuilder sb = new StringBuilder();
        sb.append('(');
        int bit = 1;
        for (int ii=0; ii<Integer.SIZE; ii++) {
            if ((value_type & bit) != 0) {
                sb.append(getValueTypeName(bit));
                sb.append(' ');
            }
            bit <<= 1;
        }
        sb.append(')');
        return sb.toString();
    }

    /**
     * from a values authoritative type (the type of the original data
     * for the value) and the desired type this returns the conversion
     * functions id, or throws a CantConvertException in the event the
     * authoritative type cannot be cast to the desired type.
     * @param authoritative_type
     * @param new_type
     * @return id of the conversion function required
     */
    protected final static int getConversionFnid(int authoritative_type, int new_type) {
        if (new_type == authoritative_type) return 0;
        switch (new_type) {
            case AS_TYPE.null_value:
                assert( authoritative_type == AS_TYPE.string_value );
                return from_string_conversion[AS_TYPE.null_value];
            case AS_TYPE.boolean_value:
                assert( authoritative_type == AS_TYPE.string_value );
                return from_string_conversion[AS_TYPE.boolean_value];
            case AS_TYPE.int_value:
                return to_int_conversion[authoritative_type];
            case AS_TYPE.long_value:
                return to_long_conversion[authoritative_type];
            case AS_TYPE.bigInteger_value:
                return to_bigInteger_conversion[authoritative_type];
            case AS_TYPE.decimal_value:
                return to_decimal_conversion[authoritative_type];
            case AS_TYPE.double_value:
                return to_double_conversion[authoritative_type];
            case AS_TYPE.string_value:
                return to_string_conversions[authoritative_type];
            case AS_TYPE.date_value:
                assert( authoritative_type == AS_TYPE.timestamp_value );
                return FNID_FROM_TIMESTAMP_TO_DATE;
            case AS_TYPE.timestamp_value:
                assert( authoritative_type == AS_TYPE.date_value );
                return FNID_FROM_DATE_TO_TIMESTAMP;
        }
        String message = "can't convert from "
                       + getValueTypeName(authoritative_type)
                       + " to "
                       + getValueTypeName(new_type);
        throw new CantConvertException(message);
    }

    public static class ConversionException extends IonException {
        private static final long serialVersionUID = 1L;
        ConversionException(String msg) {
            super(msg);
        }
        ConversionException(Exception e) {
            super(e);
        }
        ConversionException(String msg, Exception e) {
            super(msg, e);
        }
    }
    static public class CantConvertException extends ConversionException {
        private static final long serialVersionUID = 1L;
        CantConvertException(String msg) {
            super(msg);
        }
        CantConvertException(Exception e) {
            super(e);
        }
        CantConvertException(String msg, Exception e) {
            super(msg, e);
        }
    }
    static public class ValueNotSetException extends ConversionException {
        private static final long serialVersionUID = 1L;
        ValueNotSetException(String msg) {
            super(msg);
        }
        ValueNotSetException(Exception e) {
            super(e);
        }
        ValueNotSetException(String msg, Exception e) {
            super(msg, e);
        }
    }

    public static final class ValueVariant
    {
        private static final BigInteger min_int_value = BigInteger.valueOf(Integer.MIN_VALUE);
        private static final BigInteger max_int_value = BigInteger.valueOf(Integer.MAX_VALUE);
        private static final BigInteger min_long_value = BigInteger.valueOf(Long.MIN_VALUE);
        private static final BigInteger max_long_value = BigInteger.valueOf(Long.MAX_VALUE);
        private static final BigDecimal min_int_decimal_value = BigDecimal.valueOf(Integer.MIN_VALUE);
        private static final BigDecimal max_int_decimal_value = BigDecimal.valueOf(Integer.MAX_VALUE);
        private static final BigDecimal min_long_decimal_value = BigDecimal.valueOf(Long.MIN_VALUE);
        private static final BigDecimal max_long_decimal_value = BigDecimal.valueOf(Long.MAX_VALUE);

        // member variables for the variant
        int         _authoritative_type_idx;             // the original type - this not the bit mask
        int         _types_set;                          // all the various type it's been cast to (includes the original)
        boolean     _is_null;
        IonType     _null_type;
        boolean     _boolean_value;
        int         _int_value;
        long        _long_value;
        double      _double_value;
        String      _string_value;
        BigInteger  _bigInteger_value;
        Decimal     _decimal_value;
        Date        _date_value;
        Timestamp   _timestamp_value;

        //
        // public accessors
        //
        public final boolean isEmpty() {
            return (_authoritative_type_idx == 0);
        }
        public final void clear() {
            _authoritative_type_idx = 0;
            _types_set = 0;
        }
        public final boolean hasValueOfType(int value_type) {
            return ((_types_set & AS_TYPE.idx_to_bit_mask(value_type)) != 0);
        }
        public final boolean hasNumericType() {
            return ((AS_TYPE.numeric_types & _types_set) != 0);
        }
        public static final boolean isNumericType(int type_idx) {
            int type_flag = AS_TYPE.idx_to_bit_mask(type_idx);
            return ((AS_TYPE.numeric_types & type_flag) != 0);
        }
        public final boolean hasDatetimeType() {
            return ((AS_TYPE.datetime_types & _types_set) != 0);
        }
        public final void setAuthoritativeType(int value_type) {
            if (_authoritative_type_idx == value_type) return;
            if (!hasValueOfType(value_type)) {
                String message = "you must set the "
                               + getValueTypeName(value_type)
                               + " value before you can set the authoritative type to "
                               + getValueTypeName(value_type);
                throw new IllegalStateException(message);
            }
            _authoritative_type_idx = value_type;
        }
        public final void setValueToNull(IonType t) {
            _is_null = true;
            _null_type = t;
            set_value_type(AS_TYPE.null_value);
        }
        public final void setValue(boolean value) {
            _boolean_value = value;
            set_value_type(AS_TYPE.boolean_value);
        }
        public final void setValue(int value) {
            _int_value = value;
            set_value_type(AS_TYPE.int_value);
        }
        public final void setValue(long value) {
            _long_value = value;
            set_value_type(AS_TYPE.long_value);
        }
        public final void setValue(double value) {
            _double_value = value;
            set_value_type(AS_TYPE.double_value);
        }
        public final void setValue(String value) {
            _string_value = value;
            set_value_type(AS_TYPE.string_value);
        }
        public final void setValue(BigInteger value) {
            _bigInteger_value = value;
            set_value_type(AS_TYPE.bigInteger_value);
        }
        public final void setValue(Decimal value) {
            _decimal_value = value;
            set_value_type(AS_TYPE.decimal_value);
        }
        public final void setValue(Date value) {
            _date_value = value;
            set_value_type(AS_TYPE.date_value);
        }
        public final void setValue(Timestamp value) {
            _timestamp_value = value;
            set_value_type(AS_TYPE.timestamp_value);
        }

        public final void addValueToNull(IonType t) {
            _is_null = true;
            _null_type = t;
            add_value_type(AS_TYPE.null_value);
        }
        public final void addValue(boolean value) {
            _boolean_value = value;
            add_value_type(AS_TYPE.boolean_value);
        }
        public final void addValue(int value) {
            _int_value = value;
            add_value_type(AS_TYPE.int_value);
        }
        public final void addValue(long value) {
            _long_value = value;
            add_value_type(AS_TYPE.long_value);
        }
        public final void addValue(double value) {
            _double_value = value;
            add_value_type(AS_TYPE.double_value);
        }
        public final void addValue(String value) {
            _string_value = value;
            add_value_type(AS_TYPE.string_value);
        }
        public final void addValue(BigInteger value) {
            _bigInteger_value = value;
            add_value_type(AS_TYPE.bigInteger_value);
        }
        public final void addValue(BigDecimal value) {
            _decimal_value = (Decimal)value;
            add_value_type(AS_TYPE.decimal_value);
        }
        public final void addValue(Decimal value) {
            _decimal_value = value;
            add_value_type(AS_TYPE.decimal_value);
        }
        public final void addValue(Date value) {
            _date_value = value;
            add_value_type(AS_TYPE.date_value);
        }
        public final void addValue(Timestamp value) {
            _timestamp_value = value;
            add_value_type(AS_TYPE.timestamp_value);
        }


        public final int getAuthoritativeType() {
            return _authoritative_type_idx;
        }
        public final boolean isNull() {
            return (hasValueOfType(AS_TYPE.null_value));
        }
        public final IonType getNullType() {
            if (!hasValueOfType(AS_TYPE.null_value)) throw new ValueNotSetException("null value not set");
            return _null_type;
        }
        public final boolean getBoolean() {
            if (!hasValueOfType(AS_TYPE.boolean_value)) throw new ValueNotSetException("boolean not set");
            return _boolean_value;
        }
        public final int getInt() {
            if (!hasValueOfType(AS_TYPE.int_value)) throw new ValueNotSetException("int value not set");
            return _int_value;
        }
        public final long getLong() {
            if (!hasValueOfType(AS_TYPE.long_value)) throw new ValueNotSetException("long value not set");
            return _long_value;
        }
        public final double getDouble() {
            if (!hasValueOfType(AS_TYPE.double_value)) throw new ValueNotSetException("double value not set");
            return _double_value;
        }
        public final String getString() {
            if (!hasValueOfType(AS_TYPE.string_value)) throw new ValueNotSetException("String value not set");
            return _string_value;
        }
        public final BigInteger getBigInteger() {
            if (!hasValueOfType(AS_TYPE.bigInteger_value)) throw new ValueNotSetException("BigInteger value not set");
            return _bigInteger_value;
        }
        public final BigDecimal getBigDecimal() {
            if (!hasValueOfType(AS_TYPE.decimal_value)) throw new ValueNotSetException("BigDecimal value not set");
            return Decimal.bigDecimalValue(_decimal_value);
        }
        public final Decimal getDecimal() {
            if (!hasValueOfType(AS_TYPE.decimal_value)) throw new ValueNotSetException("BigDecimal value not set");
            return _decimal_value;
        }
        public final Date getDate() {
            if (!hasValueOfType(AS_TYPE.date_value)) throw new ValueNotSetException("Date value not set");
            return _date_value;
        }
        public final Timestamp getTimestamp() {
            if (!hasValueOfType(AS_TYPE.timestamp_value)) throw new ValueNotSetException("timestamp value not set");
            return _timestamp_value;
        }

        public final boolean can_convert(int new_type) {
            boolean can = false;

            switch (new_type) {
                case AS_TYPE.null_value:
                case AS_TYPE.boolean_value:
                    can = (_authoritative_type_idx == AS_TYPE.string_value);
                    break;

                case AS_TYPE.int_value:
                case AS_TYPE.long_value:
                case AS_TYPE.bigInteger_value:
                case AS_TYPE.decimal_value:
                case AS_TYPE.double_value:
                    can = (is_numeric_type(_authoritative_type_idx) || (_authoritative_type_idx == AS_TYPE.string_value));
                    break;

                case AS_TYPE.string_value:
                    can = true;
                    break;

                case AS_TYPE.date_value:
                case AS_TYPE.timestamp_value:
                    can = (is_datetime_type(_authoritative_type_idx) || (_authoritative_type_idx == AS_TYPE.string_value));
                    break;

                default:
                    can = false;
                    break;
            }
            assert( can ? (get_conversion_fnid(new_type) != -1) : (get_conversion_fnid(new_type) == -1));
            return can;
        }

        public final int get_conversion_fnid(int new_type) {
            return _Private_ScalarConversions.getConversionFnid(_authoritative_type_idx, new_type);
        }

        public final void cast(int castfnid) {
            switch(castfnid) {
            case FNID_FROM_STRING_TO_NULL:           fn_from_string_to_null();                break;
            case FNID_FROM_STRING_TO_BOOLEAN:        fn_from_string_to_boolean();             break;
            case FNID_FROM_STRING_TO_INT:            fn_from_string_to_int();                 break;
            case FNID_FROM_STRING_TO_LONG:           fn_from_string_to_long();                break;
            case FNID_FROM_STRING_TO_BIGINTEGER:     fn_from_string_to_biginteger();          break;
            case FNID_FROM_STRING_TO_DECIMAL:        fn_from_string_to_decimal();             break;
            case FNID_FROM_STRING_TO_DOUBLE:         fn_from_string_to_double();              break;
            case FNID_FROM_STRING_TO_DATE:           fn_from_string_to_date();                break;
            case FNID_FROM_STRING_TO_TIMESTAMP:      fn_from_string_to_timestamp();           break;
            case FNID_FROM_NULL_TO_STRING:           fn_from_null_to_string();                break;
            case FNID_FROM_BOOLEAN_TO_STRING:        fn_from_boolean_to_string();             break;
            case FNID_FROM_INT_TO_STRING:            fn_from_int_to_string();                 break;
            case FNID_FROM_LONG_TO_STRING:           fn_from_long_to_string();                break;
            case FNID_FROM_BIGINTEGER_TO_STRING:     fn_from_biginteger_to_string();          break;
            case FNID_FROM_DECIMAL_TO_STRING:        fn_from_decimal_to_string();             break;
            case FNID_FROM_DOUBLE_TO_STRING:         fn_from_double_to_string();              break;
            case FNID_FROM_DATE_TO_STRING:           fn_from_date_to_string();                break;
            case FNID_FROM_TIMESTAMP_TO_STRING:      fn_from_timestamp_to_string();           break;
            case FNID_FROM_LONG_TO_INT:              fn_from_long_to_int();                   break;
            case FNID_FROM_BIGINTEGER_TO_INT:        fn_from_biginteger_to_int();             break;
            case FNID_FROM_DECIMAL_TO_INT:           fn_from_decimal_to_int();                break;
            case FNID_FROM_DOUBLE_TO_INT:            fn_from_double_to_int();                 break;
            case FNID_FROM_INT_TO_LONG:              fn_from_int_to_long();                   break;
            case FNID_FROM_BIGINTEGER_TO_LONG:       fn_from_biginteger_to_long();            break;
            case FNID_FROM_DECIMAL_TO_LONG:          fn_from_decimal_to_long();               break;
            case FNID_FROM_DOUBLE_TO_LONG:           fn_from_double_to_long();                break;
            case FNID_FROM_INT_TO_BIGINTEGER:        fn_from_int_to_biginteger();             break;
            case FNID_FROM_LONG_TO_BIGINTEGER:       fn_from_long_to_biginteger();            break;
            case FNID_FROM_DECIMAL_TO_BIGINTEGER:    fn_from_decimal_to_biginteger();         break;
            case FNID_FROM_DOUBLE_TO_BIGINTEGER:     fn_from_double_to_biginteger();          break;
            case FNID_FROM_INT_TO_DECIMAL:           fn_from_int_to_decimal();                break;
            case FNID_FROM_LONG_TO_DECIMAL:          fn_from_long_to_decimal();               break;
            case FNID_FROM_BIGINTEGER_TO_DECIMAL:    fn_from_biginteger_to_decimal();         break;
            case FNID_FROM_DOUBLE_TO_DECIMAL:        fn_from_double_to_decimal();             break;
            case FNID_FROM_INT_TO_DOUBLE:            fn_from_int_to_double();                 break;
            case FNID_FROM_LONG_TO_DOUBLE:           fn_from_long_to_double();                break;
            case FNID_FROM_BIGINTEGER_TO_DOUBLE:     fn_from_biginteger_to_double();          break;
            case FNID_FROM_DECIMAL_TO_DOUBLE:        fn_from_decimal_to_double();             break;
            case FNID_FROM_TIMESTAMP_TO_DATE:        fn_from_timestamp_to_date();             break;
            case FNID_FROM_DATE_TO_TIMESTAMP:        fn_from_date_to_timestamp();             break;
            default: throw new ConversionException("unrecognized conversion fnid ["+castfnid+"]invoked");
            }
        }

        private final void set_value_type(int type_idx) {
            _types_set = AS_TYPE.idx_to_bit_mask(type_idx);
            _authoritative_type_idx = type_idx;
        }
        private final void add_value_type(int type_idx) {
            _types_set |= AS_TYPE.idx_to_bit_mask(type_idx);
        }
        private final boolean is_numeric_type(int type_idx) {
            return (AS_TYPE.numeric_types & AS_TYPE.idx_to_bit_mask(type_idx)) != 0;
        }
        private final boolean is_datetime_type(int type_idx) {
            return (AS_TYPE.datetime_types & AS_TYPE.idx_to_bit_mask(type_idx)) != 0;
        }

        private final void fn_from_string_to_null() {
            _null_type = IonTokenConstsX.getNullType(_string_value);
            _is_null = true;
            add_value_type(AS_TYPE.null_value);
        }
        private final void fn_from_string_to_boolean() {
            _boolean_value = Boolean.parseBoolean(_string_value);
            add_value_type(AS_TYPE.boolean_value);
        }
        private final void fn_from_string_to_int() {
            _int_value = Integer.parseInt(_string_value);
            add_value_type(AS_TYPE.int_value);
        }
        private final void fn_from_string_to_long() {
            _long_value = Long.parseLong(_string_value);
            add_value_type(AS_TYPE.long_value);
        }
        private final void fn_from_string_to_biginteger() {
            _bigInteger_value = new BigInteger(_string_value);
            add_value_type(AS_TYPE.bigInteger_value);
        }
        private final void fn_from_string_to_decimal() {
            _decimal_value = Decimal.valueOf(_string_value);
            add_value_type(AS_TYPE.decimal_value);
        }
        private final void fn_from_string_to_double() {
            _double_value = Double.parseDouble(_string_value);
            add_value_type(AS_TYPE.double_value);
        }
        private final void fn_from_string_to_date() {
            if (!hasValueOfType(AS_TYPE.timestamp_value)) {
                fn_from_string_to_timestamp();
            }
            _date_value = new Date(_timestamp_value.getMillis());
            add_value_type(AS_TYPE.date_value);
        }
        private final void fn_from_string_to_timestamp() {
            _timestamp_value = Timestamp.valueOf(_string_value);
            add_value_type(AS_TYPE.timestamp_value);
            add_value_type(AS_TYPE.timestamp_value);
        }
        private final void fn_from_null_to_string() {
            _string_value = IonTokenConstsX.getNullImage(_null_type);
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_boolean_to_string() {
            _string_value = _boolean_value ? "true" : "false";
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_int_to_string() {
            _string_value = Integer.toString(_int_value);
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_long_to_string() {
            _string_value = Long.toString(_long_value);
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_biginteger_to_string() {
            _string_value = _bigInteger_value.toString();
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_decimal_to_string() {
            _string_value = _decimal_value.toString();
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_double_to_string() {
            _string_value = Double.toString(_double_value);
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_date_to_string() {
            if (!hasValueOfType(AS_TYPE.timestamp_value)) {
                fn_from_date_to_timestamp();
            }
            fn_from_timestamp_to_string();
        }
        private final void fn_from_timestamp_to_string() {
            _string_value = _timestamp_value.toString();
            add_value_type(AS_TYPE.string_value);
        }
        private final void fn_from_long_to_int() {
            if (_long_value < Integer.MIN_VALUE || _long_value > Integer.MAX_VALUE) {
                throw new CantConvertException("long is too large to fit in an int");
            }
            _int_value = (int)_long_value;
            add_value_type(AS_TYPE.int_value);
        }
        private final void fn_from_biginteger_to_int() {
            if (min_int_value.compareTo(_bigInteger_value) > 0
             || max_int_value.compareTo(_bigInteger_value) < 0
            ) {
                throw new CantConvertException("bigInteger value is too large to fit in an int");
            }
            _int_value = _bigInteger_value.intValue();
            add_value_type(AS_TYPE.int_value);
        }
        private final void fn_from_decimal_to_int() {
            if (min_int_decimal_value.compareTo(_decimal_value) > 0
             || max_int_decimal_value.compareTo(_decimal_value) < 0
             ) {
                throw new CantConvertException("BigDecimal value is too large to fit in an int");
            }
            _int_value = _decimal_value.intValue();
            add_value_type(AS_TYPE.int_value);
        }
        private final void fn_from_double_to_int() {
            if (_double_value < Integer.MIN_VALUE
             || _double_value > Integer.MAX_VALUE
            ) {
                throw new CantConvertException("double is too large to fit in an int");
            }
            _int_value = (int)_double_value;
            add_value_type(AS_TYPE.int_value);
        }
        private final void fn_from_int_to_long() {
            _long_value = _int_value;
            add_value_type(AS_TYPE.long_value);
        }
        private final void fn_from_biginteger_to_long() {
            if (min_long_value.compareTo(_bigInteger_value) > 0
             || max_long_value.compareTo(_bigInteger_value) < 0
            ) {
                throw new CantConvertException("BigInteger is too large to fit in a long");
            }
            _long_value = _bigInteger_value.longValue();
            add_value_type(AS_TYPE.long_value);
        }
        private final void fn_from_decimal_to_long() {
            if (min_long_decimal_value.compareTo(_decimal_value) > 0
             || max_long_decimal_value.compareTo(_decimal_value) < 0
            ) {
                throw new CantConvertException("BigDecimal value is too large to fit in a long");
            }
            _long_value = _decimal_value.longValue();
            add_value_type(AS_TYPE.long_value);
        }
        private final void fn_from_double_to_long() {
            if (_double_value < Long.MIN_VALUE
             || _double_value > Long.MAX_VALUE
            ) {
                throw new CantConvertException("double is too large to fit in a long");
            }
            _long_value = (long)_double_value;
            add_value_type(AS_TYPE.long_value);
        }
        private final void fn_from_int_to_biginteger() {
            _bigInteger_value = BigInteger.valueOf(_int_value);
            add_value_type(AS_TYPE.bigInteger_value);
        }
        private final void fn_from_long_to_biginteger() {
            _bigInteger_value = BigInteger.valueOf(_long_value);
            add_value_type(AS_TYPE.bigInteger_value);
        }
        private final void fn_from_decimal_to_biginteger() {
            _bigInteger_value = _decimal_value.toBigInteger();
            add_value_type(AS_TYPE.bigInteger_value);
        }
        private final void fn_from_double_to_biginteger() {
            // To avoid decapitating values that are > Long.MAX_VALUE, we must
            // convert to BigDecimal first.
            _bigInteger_value =
                Decimal.valueOf(_double_value).toBigInteger();
            add_value_type(AS_TYPE.bigInteger_value);
        }
        private final void fn_from_int_to_decimal() {
            _decimal_value = Decimal.valueOf(_int_value);
            add_value_type(AS_TYPE.decimal_value);
        }
        private final void fn_from_long_to_decimal() {
            _decimal_value = Decimal.valueOf(_long_value);
            add_value_type(AS_TYPE.decimal_value);
        }
        private final void fn_from_biginteger_to_decimal() {
            _decimal_value = Decimal.valueOf(_bigInteger_value);
            add_value_type(AS_TYPE.decimal_value);
        }
        private final void fn_from_double_to_decimal() {
            _decimal_value = Decimal.valueOf(_double_value);
            add_value_type(AS_TYPE.decimal_value);
        }
        private final void fn_from_int_to_double() {
            _double_value = _int_value;
            add_value_type(AS_TYPE.double_value);
        }
        private final void fn_from_long_to_double() {
            _double_value = _long_value;
            add_value_type(AS_TYPE.double_value);
        }
        private final void fn_from_biginteger_to_double() {
            _double_value = _bigInteger_value.doubleValue();
            add_value_type(AS_TYPE.double_value);
        }
        private final void fn_from_decimal_to_double() {
            _double_value = _decimal_value.doubleValue();
            add_value_type(AS_TYPE.double_value);
        }
        private final void fn_from_timestamp_to_date() {
            _date_value = _timestamp_value.dateValue();
            add_value_type(AS_TYPE.date_value);
        }
        private final void fn_from_date_to_timestamp() {
            _timestamp_value = new Timestamp(_date_value.getTime(), null);
            add_value_type(AS_TYPE.timestamp_value);
        }
    }
}