Package com.facebook.presto.byteCode.expression

Source Code of com.facebook.presto.byteCode.expression.CastByteCodeExpression

/*
* Licensed 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 com.facebook.presto.byteCode.expression;

import com.facebook.presto.byteCode.Block;
import com.facebook.presto.byteCode.ByteCodeNode;
import com.facebook.presto.byteCode.OpCode;
import com.facebook.presto.byteCode.ParameterizedType;
import com.google.common.collect.ImmutableList;

import java.util.List;

import static com.facebook.presto.byteCode.ParameterizedType.type;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.primitives.Primitives.wrap;
import static java.lang.String.format;

class CastByteCodeExpression
        extends ByteCodeExpression
{
    private final ByteCodeExpression instance;

    public CastByteCodeExpression(ByteCodeExpression instance, ParameterizedType type)
    {
        super(type);

        this.instance = checkNotNull(instance, "instance is null");

        checkArgument(type.getPrimitiveType() != void.class, "Type %s can not be cast to %s", instance.getType(), type);

        // if we have a primitive to object or object to primitive conversion, it must be an exact boxing or unboxing conversion
        if (instance.getType().isPrimitive() != type.isPrimitive()) {
            checkArgument(unwrapPrimitiveType(instance.getType()) == unwrapPrimitiveType(type), "Type %s can not be cast to %s", instance.getType(), type);
        }
    }

    @Override
    public ByteCodeNode getByteCode()
    {
        Block block = new Block(null).append(instance.getByteCode());

        if (instance.getType().isPrimitive()) {
            Class<?> sourceType = instance.getType().getPrimitiveType();
            castPrimitiveToPrimitive(block, sourceType, unwrapPrimitiveType(getType()));

            // insert boxing conversion
            if (!getType().isPrimitive()) {
                Class<?> primitiveTargetType = unwrapPrimitiveType(getType());
                return block.invokeStatic(getType(), "valueOf", getType(), type(primitiveTargetType));
            }

            return block;
        }
        else if (getType().isPrimitive()) {
            // unbox
            Class<?> targetType = getType().getPrimitiveType();
            return block.invokeVirtual(wrap(targetType), targetType.getSimpleName() + "Value", targetType);
        }
        else {
            block.checkCast(getType());
        }
        return block;
    }

    private static Block castPrimitiveToPrimitive(Block block, Class<?> sourceType, Class<?> targetType)
    {
        if (sourceType == byte.class) {
            if (targetType == byte.class) {
                return block;
            }
            if (targetType == char.class) {
                return block;
            }
            if (targetType == short.class) {
                return block;
            }
            if (targetType == int.class) {
                return block;
            }
            if (targetType == long.class) {
                return block.append(OpCode.I2L);
            }
            if (targetType == float.class) {
                return block.append(OpCode.I2F);
            }
            if (targetType == double.class) {
                return block.append(OpCode.I2D);
            }
        }
        if (sourceType == char.class) {
            if (targetType == byte.class) {
                return block.append(OpCode.I2B);
            }
            if (targetType == char.class) {
                return block;
            }
            if (targetType == short.class) {
                return block;
            }
            if (targetType == int.class) {
                return block;
            }
            if (targetType == long.class) {
                return block.append(OpCode.I2L);
            }
            if (targetType == float.class) {
                return block.append(OpCode.I2F);
            }
            if (targetType == double.class) {
                return block.append(OpCode.I2D);
            }
        }
        if (sourceType == short.class) {
            if (targetType == byte.class) {
                return block.append(OpCode.I2B);
            }
            if (targetType == char.class) {
                return block.append(OpCode.I2C);
            }
            if (targetType == short.class) {
                return block;
            }
            if (targetType == int.class) {
                return block;
            }
            if (targetType == long.class) {
                return block.append(OpCode.I2L);
            }
            if (targetType == float.class) {
                return block.append(OpCode.I2F);
            }
            if (targetType == double.class) {
                return block.append(OpCode.I2D);
            }
        }
        if (sourceType == int.class) {
            if (targetType == byte.class) {
                return block.append(OpCode.I2B);
            }
            if (targetType == char.class) {
                return block.append(OpCode.I2C);
            }
            if (targetType == short.class) {
                return block.append(OpCode.I2S);
            }
            if (targetType == int.class) {
                return block;
            }
            if (targetType == long.class) {
                return block.append(OpCode.I2L);
            }
            if (targetType == float.class) {
                return block.append(OpCode.I2F);
            }
            if (targetType == double.class) {
                return block.append(OpCode.I2D);
            }
        }
        if (sourceType == long.class) {
            if (targetType == byte.class) {
                return block.append(OpCode.L2I).append(OpCode.I2B);
            }
            if (targetType == char.class) {
                return block.append(OpCode.L2I).append(OpCode.I2C);
            }
            if (targetType == short.class) {
                return block.append(OpCode.L2I).append(OpCode.I2S);
            }
            if (targetType == int.class) {
                return block.append(OpCode.L2I);
            }
            if (targetType == long.class) {
                return block;
            }
            if (targetType == float.class) {
                return block.append(OpCode.L2F);
            }
            if (targetType == double.class) {
                return block.append(OpCode.L2D);
            }
        }
        if (sourceType == float.class) {
            if (targetType == byte.class) {
                return block.append(OpCode.F2I).append(OpCode.I2B);
            }
            if (targetType == char.class) {
                return block.append(OpCode.F2I).append(OpCode.I2C);
            }
            if (targetType == short.class) {
                return block.append(OpCode.F2I).append(OpCode.I2S);
            }
            if (targetType == int.class) {
                return block.append(OpCode.F2I);
            }
            if (targetType == long.class) {
                return block.append(OpCode.F2L);
            }
            if (targetType == float.class) {
                return block;
            }
            if (targetType == double.class) {
                return block.append(OpCode.F2D);
            }
        }
        if (sourceType == double.class) {
            if (targetType == byte.class) {
                return block.append(OpCode.D2I).append(OpCode.I2B);
            }
            if (targetType == char.class) {
                return block.append(OpCode.D2I).append(OpCode.I2C);
            }
            if (targetType == short.class) {
                return block.append(OpCode.D2I).append(OpCode.I2S);
            }
            if (targetType == int.class) {
                return block.append(OpCode.D2I);
            }
            if (targetType == long.class) {
                return block.append(OpCode.D2L);
            }
            if (targetType == float.class) {
                return block.append(OpCode.D2F);
            }
            if (targetType == double.class) {
                return block;
            }
        }
        throw new IllegalArgumentException(format("Type %s can not be cast to %s", sourceType, targetType));
    }

    private static Class<?> unwrapPrimitiveType(ParameterizedType type)
    {
        if (type.isPrimitive()) {
            return type.getPrimitiveType();
        }
        switch (type.getJavaClassName()) {
            case "java.lang.Byte":
                return byte.class;
            case "java.lang.Character":
                return char.class;
            case "java.lang.Short":
                return short.class;
            case "java.lang.Integer":
                return int.class;
            case "java.lang.Long":
                return long.class;
            case "java.lang.Float":
                return float.class;
            case "java.lang.Double":
                return double.class;
            default:
                return null;
        }
    }

    @Override
    protected String formatOneLine()
    {
        return "((" + getType().getSimpleName() + ") " + instance + ")";
    }

    @Override
    public List<ByteCodeNode> getChildNodes()
    {
        return ImmutableList.<ByteCodeNode>of(instance);
    }
}
TOP

Related Classes of com.facebook.presto.byteCode.expression.CastByteCodeExpression

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.