Package com.facebook.presto.metadata

Source Code of com.facebook.presto.metadata.Signature

/*
* 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.metadata;

import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.spi.type.TypeSignature;
import com.facebook.presto.type.UnknownType;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;

import javax.annotation.Nullable;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.facebook.presto.metadata.FunctionRegistry.canCoerce;
import static com.facebook.presto.metadata.FunctionRegistry.mangleOperatorName;
import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

public final class Signature
{
    private final String name;
    private final List<TypeParameter> typeParameters;
    private final TypeSignature returnType;
    private final List<TypeSignature> argumentTypes;
    private final boolean variableArity;
    private final boolean internal;

    @JsonCreator
    public Signature(
            @JsonProperty("name") String name,
            @JsonProperty("typeParameters") List<TypeParameter> typeParameters,
            @JsonProperty("returnType") String returnType,
            @JsonProperty("argumentTypes") List<String> argumentTypes,
            @JsonProperty("variableArity") boolean variableArity,
            @JsonProperty("internal") boolean internal)
    {
        checkNotNull(name, "name is null");
        checkNotNull(typeParameters, "typeParameters is null");
        checkNotNull(returnType, "returnType is null");
        checkNotNull(argumentTypes, "argumentTypes is null");

        this.name = name;
        this.typeParameters = ImmutableList.copyOf(typeParameters);
        this.returnType = parseTypeSignature(checkNotNull(returnType, "returnType is null"));
        this.argumentTypes = FluentIterable.from(argumentTypes).transform(new Function<String, TypeSignature>()
        {
            @Override
            public TypeSignature apply(String input)
            {
                checkNotNull(input, "input is null");
                return parseTypeSignature(input);
            }
        }).toList();
        this.variableArity = variableArity;
        this.internal = internal;
    }

    public Signature(String name, String returnType, List<String> argumentTypes)
    {
        this(name, ImmutableList.<TypeParameter>of(), returnType, argumentTypes, false, false);
    }

    public Signature(String name, String returnType, String... argumentTypes)
    {
        this(name, returnType, ImmutableList.copyOf(argumentTypes));
    }

    public static Signature internalOperator(String name, String returnType, List<String> argumentTypes)
    {
        return internalFunction(mangleOperatorName(name), returnType, argumentTypes);
    }

    public static Signature internalOperator(String name, String returnType, String... argumentTypes)
    {
        return internalFunction(mangleOperatorName(name), returnType, ImmutableList.copyOf(argumentTypes));
    }

    public static Signature internalFunction(String name, String returnType, String... argumentTypes)
    {
        return internalFunction(name, returnType, ImmutableList.copyOf(argumentTypes));
    }

    public static Signature internalFunction(String name, String returnType, List<String> argumentTypes)
    {
        return new Signature(name, ImmutableList.<TypeParameter>of(), returnType, argumentTypes, false, true);
    }

    @JsonProperty
    public String getName()
    {
        return name;
    }

    @JsonProperty
    public String getReturnType()
    {
        return returnType.toString();
    }

    @JsonProperty
    public List<String> getArgumentTypes()
    {
        return FluentIterable.from(argumentTypes).transform(new Function<TypeSignature, String>() {
            @Override
            public String apply(TypeSignature input)
            {
                return input.toString();
            }
        }).toList();
    }

    @JsonProperty
    public boolean isInternal()
    {
        return internal;
    }

    @JsonProperty
    public boolean isVariableArity()
    {
        return variableArity;
    }

    @JsonProperty
    public List<TypeParameter> getTypeParameters()
    {
        return typeParameters;
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(name, typeParameters, returnType, argumentTypes, variableArity, internal);
    }

    Signature withAlias(String name)
    {
        return new Signature(name, typeParameters, getReturnType(), getArgumentTypes(), variableArity, internal);
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Signature other = (Signature) obj;
        return Objects.equals(this.name, other.name) &&
                Objects.equals(this.typeParameters, other.typeParameters) &&
                Objects.equals(this.returnType, other.returnType) &&
                Objects.equals(this.argumentTypes, other.argumentTypes) &&
                Objects.equals(this.variableArity, other.variableArity) &&
                Objects.equals(this.internal, other.internal);
    }

    @Override
    public String toString()
    {
        return (internal ? "%" : "") + name + (typeParameters.isEmpty() ? "" : "<" + Joiner.on(",").join(typeParameters) + ">") + "(" + Joiner.on(",").join(argumentTypes) + "):" + returnType;
    }

    @Nullable
    public Map<String, Type> bindTypeParameters(Type returnType, List<? extends Type> types, boolean allowCoercion, TypeManager typeManager)
    {
        Map<String, Type> boundParameters = new HashMap<>();
        Map<String, TypeParameter> unboundParameters = new HashMap<>();
        for (TypeParameter parameter : typeParameters) {
            unboundParameters.put(parameter.getName(), parameter);
        }

        if (!matchAndBind(boundParameters, unboundParameters, this.returnType, returnType, allowCoercion, typeManager)) {
            return null;
        }

        if (!matchArguments(boundParameters, unboundParameters, argumentTypes, types, allowCoercion, variableArity, typeManager)) {
            return null;
        }

        return boundParameters;
    }

    @Nullable
    public Map<String, Type> bindTypeParameters(List<? extends Type> types, boolean allowCoercion, TypeManager typeManager)
    {
        Map<String, Type> boundParameters = new HashMap<>();
        Map<String, TypeParameter> unboundParameters = new HashMap<>();
        for (TypeParameter parameter : typeParameters) {
            unboundParameters.put(parameter.getName(), parameter);
        }

        if (!matchArguments(boundParameters, unboundParameters, argumentTypes, types, allowCoercion, variableArity, typeManager)) {
            return null;
        }

        return boundParameters;
    }

    private static boolean matchArguments(
            Map<String, Type> boundParameters,
            Map<String, TypeParameter> unboundParameters,
            List<TypeSignature> argumentTypes,
            List<? extends Type> types,
            boolean allowCoercion,
            boolean varArgs,
            TypeManager typeManager)
    {
        if (varArgs) {
            if (types.size() < argumentTypes.size() - 1) {
                return false;
            }
        }
        else {
            if (argumentTypes.size() != types.size()) {
                return false;
            }
        }

        for (int i = 0; i < types.size(); i++) {
            // Get the current argument signature, or the last one, if this is a varargs function
            TypeSignature typeSignature = argumentTypes.get(Math.min(i, argumentTypes.size() - 1));
            Type type = types.get(i);
            if (!matchAndBind(boundParameters, unboundParameters, typeSignature, type, allowCoercion, typeManager)) {
                return false;
            }
        }

        return true;
    }

    private static boolean matchAndBind(Map<String, Type> boundParameters, Map<String, TypeParameter> unboundParameters, TypeSignature signature, Type type, boolean allowCoercion, TypeManager typeManager)
    {
        // If this parameter is already bound, then match (with coercion)
        if (boundParameters.containsKey(signature.getBase())) {
            checkArgument(signature.getParameters().isEmpty(), "Unexpected parameteric type");
            if (allowCoercion) {
                return canCoerce(type, boundParameters.get(signature.getBase()));
            }
            else {
                return type.equals(boundParameters.get(signature.getBase()));
            }
        }

        // Recurse into component types
        if (!signature.getParameters().isEmpty()) {
            if (type.getTypeParameters().size() != signature.getParameters().size()) {
                return false;
            }
            for (int i = 0; i < signature.getParameters().size(); i++) {
                Type componentType = type.getTypeParameters().get(i);
                TypeSignature componentSignature = signature.getParameters().get(i);
                if (!matchAndBind(boundParameters, unboundParameters, componentSignature, componentType, allowCoercion, typeManager)) {
                    return false;
                }
            }
        }

        if (type.equals(UnknownType.UNKNOWN) && allowCoercion) {
            // The unknown type can be coerced to any type, so don't bind the parameters, since nothing can be coerced to the unknown type
            return true;
        }

        // Bind parameter, if this is a free type parameter
        if (unboundParameters.containsKey(signature.getBase())) {
            TypeParameter typeParameter = unboundParameters.get(signature.getBase());
            if (!typeParameter.canBind(type)) {
                return false;
            }
            unboundParameters.remove(signature.getBase());
            boundParameters.put(signature.getBase(), type);
            return true;
        }

        // We've already checked all the components, so just match the base type
        if (!signature.getParameters().isEmpty()) {
            return parseTypeSignature(type.getName()).getBase().equals(signature.getBase());
        }

        if (allowCoercion) {
            return canCoerce(type, typeManager.getType(signature.getBase()));
        }
        else {
            return type.equals(typeManager.getType(signature.getBase()));
        }
    }

    public static TypeParameter typeParameter(String name)
    {
        return new TypeParameter(name, false, false);
    }

    public static TypeParameter comparableTypeParameter(String name)
    {
        return new TypeParameter(name, true, false);
    }

    public static TypeParameter orderableTypeParameter(String name)
    {
        return new TypeParameter(name, false, true);
    }
}
TOP

Related Classes of com.facebook.presto.metadata.Signature

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.