<commit_before>/*
   Copyright 2009-2012 <NAME>

   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 org.dynalang.dynalink.support;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException;
import java.util.LinkedList;
import java.util.List;

import org.dynalang.dynalink.linker.GuardedInvocation;
import org.dynalang.dynalink.linker.GuardingTypeConverterFactory;
import org.dynalang.dynalink.linker.LinkerServices;

/**
 * A factory for type converters. This class is the main implementation behind the
 * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory}
 * instances and creates appropriate converters for method handles.
 *
 * @author <NAME>
 * @version $Id: $
 */
public class TypeConverterFactory {

    private final GuardingTypeConverterFactory[] factories;
    private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
        @Override
        protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
            return new ClassMap<MethodHandle>(sourceType.getClassLoader()) {
                @Override
                protected MethodHandle computeValue(Class<?> targetType) {
                    return createConverter(sourceType, targetType);
                }
            };
        }
    };

    /**
     * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
     *
     * @param factories the {@link GuardingTypeConverterFactory} instances to compose.
     */
    public TypeConverterFactory(Iterable<GuardingTypeConverterFactory> factories) {
        final List<GuardingTypeConverterFactory> l = new LinkedList<GuardingTypeConverterFactory>();
        for(GuardingTypeConverterFactory factory: factories) {
            l.add(factory);
        }
        this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]);

    }

    /**
     * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
     * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
     * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
     * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions,
     * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
     * provided by {@link GuardingTypeConverterFactory} implementations. It doesn't use language-specific conversions on
     * the return type.
     *
     * @param handle target method handle
     * @param fromType the types of source arguments
     * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and
     * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
     * {@link GuardingTypeConverterFactory} produced type converters as filters.
     */
    public MethodHandle asType(MethodHandle handle, final MethodType fromType) {
        MethodHandle newHandle = handle;
        final MethodType toType = newHandle.type();
        final int l = toType.parameterCount();
        if(l != fromType.parameterCount()) {
            throw new WrongMethodTypeException("Parameter counts differ");
        }
        int pos = 0;
        final List<MethodHandle> converters = new LinkedList<MethodHandle>();
        for(int i = 0; i < l; ++i) {
            final Class<?> fromParamType = fromType.parameterType(i);
            final Class<?> toParamType = toType.parameterType(i);
            if(canAutoConvert(fromParamType, toParamType)) {
                newHandle = applyConverters(newHandle, pos, converters);
            } else {
                final MethodHandle converter = getTypeConverter(fromParamType, toParamType);
                if(converter != null) {
                    if(converters.isEmpty()) {
                        pos = i;
                    }
                    converters.add(converter);
                } else {
                    newHandle = applyConverters(newHandle, pos, converters);
                }
            }
        }
        return applyConverters(newHandle, pos, converters).asType(fromType);
    }

    private static MethodHandle applyConverters(MethodHandle handle, int pos, List<MethodHandle> converters) {
        if(converters.isEmpty()) {
            return handle;
        }
        final MethodHandle newHandle =
                MethodHandles.filterArguments(handle, pos, converters.toArray(new MethodHandle[converters.size()]));
        converters.clear();
        return newHandle;
    }

    /**
     * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion,
     * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not
     * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion
     * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false
     * guarantees that it would fail.
     *
     * @param from the source type for the conversion
     * @param to the target type for the conversion
     * @return true if there can be a conversion, false if there can not.
     */
    public boolean canConvert(final Class<?> from, final Class<?> to) {
        return canAutoConvert(from, to) || getTypeConverter(from, to) != null;
    }

    /**
     * Determines whether it's safe to perform an automatic conversion between the source and target class.
     *
     * @param fromType convert from this class
     * @param toType convert to this class
     * @return true if it's safe to let MethodHandles.convertArguments() to handle this conversion.
     */
    private static boolean canAutoConvert(final Class<?> fromType, final Class<?> toType) {
        if(fromType.isPrimitive()) {
            if(fromType == Void.TYPE) {
                return true;
            }
            if(toType.isPrimitive()) {
                if(toType == Void.TYPE) {
                    return true;
                }
                return canAutoConvertPrimitives(fromType, toType);
            }
            return canAutoConvertPrimitiveToReference(fromType, toType);
        }
        if(toType.isPrimitive()) {
            if(toType == Void.TYPE) {
                return true;
            }
            return canAutoConvertPrimitiveToReference(toType, fromType);
        }
        // In all other cases, only allow automatic conversion from a class to
        // its superclass or superinterface.
        return toType.isAssignableFrom(fromType);
    }

    private static boolean canAutoConvertPrimitiveToReference(final Class<?> primitiveType, final Class<?> refType) {
        return TypeUtilities.isAssignableFromBoxedPrimitive(refType)
                && ((primitiveType != Byte.TYPE && primitiveType != Boolean.TYPE) || refType != Character.class);
    }

    private static boolean canAutoConvertPrimitives(Class<?> fromType, Class<?> toType) {
        // the only cast conversion not allowed between non-boolean primitives
        // is byte->char, all other narrowing and widening conversions are
        // allowed. boolean is converted to byte first, so same applies to it.
        return (fromType != Byte.TYPE && fromType != Boolean.TYPE) || toType != Character.TYPE;
    }

    private MethodHandle getTypeConverter(Class<?> sourceType, Class<?> targetType) {
        final MethodHandle converter = converterMap.get(sourceType).get(targetType);
        return converter == IDENTITY_CONVERSION ? null : converter;
    }

    private MethodHandle createConverter(Class<?> sourceType, Class<?> targetType) {
        final MethodType type = MethodType.methodType(targetType, sourceType);
        final MethodHandle identity = IDENTITY_CONVERSION.asType(type);
        MethodHandle last = identity;
        for(int i = factories.length; i-- > 0;) {
            final GuardedInvocation next = factories[i].convertToType(sourceType, targetType);
            if(next != null) {
                next.assertType(type);
                last = MethodHandles.guardWithTest(next.getGuard(), next.getInvocation(), last);
            }
        }
        return last == identity ? IDENTITY_CONVERSION : last;
    }

    private static final MethodHandle IDENTITY_CONVERSION = new Lookup(MethodHandles.lookup()).findStatic(
            TypeConverterFactory.class, "_identityConversion", MethodType.methodType(Object.class, Object.class));

    /**
     * This method is public for implementation reasons. Do not invoke it directly. Returns the object passed in.
     *
     * @param o the object<commit_msg>Added support for fast unconditional converters.<commit_after>/*
   Copyright 2009-2012 <NAME>

   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 org.dynalang.dynalink.support;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException;
import java.util.LinkedList;
import java.util.List;

import org.dynalang.dynalink.linker.GuardedInvocation;
import org.dynalang.dynalink.linker.GuardingTypeConverterFactory;
import org.dynalang.dynalink.linker.LinkerServices;

/**
 * A factory for type converters. This class is the main implementation behind the
 * {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory}
 * instances and creates appropriate converters for method handles.
 *
 * @author <NAME>
 * @version $Id: $
 */
public class TypeConverterFactory {

    private final GuardingTypeConverterFactory[] factories;
    private final ClassValue<ClassMap<MethodHandle>> converterMap = new ClassValue<ClassMap<MethodHandle>>() {
        @Override
        protected ClassMap<MethodHandle> computeValue(final Class<?> sourceType) {
            return new ClassMap<MethodHandle>(sourceType.getClassLoader()) {
                @Override
                protected MethodHandle computeValue(Class<?> targetType) {
                    return createConverter(sourceType, targetType);
                }
            };
        }
    };

    /**
     * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances.
     *
     * @param factories the {@link GuardingTypeConverterFactory} instances to compose.
     */
    public TypeConverterFactory(Iterable<GuardingTypeConverterFactory> factories) {
        final List<GuardingTypeConverterFactory> l = new LinkedList<GuardingTypeConverterFactory>();
        for(GuardingTypeConverterFactory factory: factories) {
            l.add(factory);
        }
        this.factories = l.toArray(new GuardingTypeConverterFactory[l.size()]);

    }

    /**
     * Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
     * {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
     * parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
     * wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions,
     * it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
     * provided by {@link GuardingTypeConverterFactory} implementations. It doesn't use language-specific conversions on
     * the return type.
     *
     * @param handle target method handle
     * @param fromType the types of source arguments
     * @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)} and
     * {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
     * {@link GuardingTypeConverterFactory} produced type converters as filters.
     */
    public MethodHandle asType(MethodHandle handle, final MethodType fromType) {
        MethodHandle newHandle = handle;
        final MethodType toType = newHandle.type();
        final int l = toType.parameterCount();
        if(l != fromType.parameterCount()) {
            throw new WrongMethodTypeException("Parameter counts differ");
        }
        int pos = 0;
        final List<MethodHandle> converters = new LinkedList<MethodHandle>();
        for(int i = 0; i < l; ++i) {
            final Class<?> fromParamType = fromType.parameterType(i);
            final Class<?> toParamType = toType.parameterType(i);
            if(canAutoConvert(fromParamType, toParamType)) {
                newHandle = applyConverters(newHandle, pos, converters);
            } else {
                final MethodHandle converter = getTypeConverter(fromParamType, toParamType);
                if(converter != null) {
                    if(converters.isEmpty()) {
                        pos = i;
                    }
                    converters.add(converter);
                } else {
                    newHandle = applyConverters(newHandle, pos, converters);
                }
            }
        }
        return applyConverters(newHandle, pos, converters).asType(fromType);
    }

    private static MethodHandle applyConverters(MethodHandle handle, int pos, List<MethodHandle> converters) {
        if(converters.isEmpty()) {
            return handle;
        }
        final MethodHandle newHandle =
                MethodHandles.filterArguments(handle, pos, converters.toArray(new MethodHandle[converters.size()]));
        converters.clear();
        return newHandle;
    }

    /**
     * Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion,
     * or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not
     * exist a conversion between the requested types. Note that returning true does not guarantee that the conversion
     * will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false
     * guarantees that it would fail.
     *
     * @param from the source type for the conversion
     * @param to the target type for the conversion
     * @return true if there can be a conversion, false if there can not.
     */
    public boolean canConvert(final Class<?> from, final Class<?> to) {
        return canAutoConvert(from, to) || getTypeConverter(from, to) != null;
    }

    /**
     * Determines whether it's safe to perform an automatic conversion between the source and target class.
     *
     * @param fromType convert from this class
     * @param toType convert to this class
     * @return true if it's safe to let MethodHandles.convertArguments() to handle this conversion.
     */
    private static boolean canAutoConvert(final Class<?> fromType, final Class<?> toType) {
        if(fromType.isPrimitive()) {
            if(fromType == Void.TYPE) {
                return true;
            }
            if(toType.isPrimitive()) {
                if(toType == Void.TYPE) {
                    return true;
                }
                return canAutoConvertPrimitives(fromType, toType);
            }
            return canAutoConvertPrimitiveToReference(fromType, toType);
        }
        if(toType.isPrimitive()) {
            if(toType == Void.TYPE) {
                return true;
            }
            return canAutoConvertPrimitiveToReference(toType, fromType);
        }
        // In all other cases, only allow automatic conversion from a class to
        // its superclass or superinterface.
        return toType.isAssignableFrom(fromType);
    }

    private static boolean canAutoConvertPrimitiveToReference(final Class<?> primitiveType, final Class<?> refType) {
        return TypeUtilities.isAssignableFromBoxedPrimitive(refType)
                && ((primitiveType != Byte.TYPE && primitiveType != Boolean.TYPE) || refType != Character.class);
    }

    private static boolean canAutoConvertPrimitives(Class<?> fromType, Class<?> toType) {
        // the only cast conversion not allowed between non-boolean primitives
        // is byte->char, all other narrowing and widening conversions are
        // allowed. boolean is converted to byte first, so same applies to it.
        return (fromType != Byte.TYPE && fromType != Boolean.TYPE) || toType != Character.TYPE;
    }

    private MethodHandle getTypeConverter(Class<?> sourceType, Class<?> targetType) {
        final MethodHandle converter = converterMap.get(sourceType).get(targetType);
        return converter == IDENTITY_CONVERSION ? null : converter;
    }

    private MethodHandle createConverter(Class<?> sourceType, Class<?> targetType) {
        final MethodType type = MethodType.methodType(targetType, sourceType);
        final MethodHandle identity = IDENTITY_CONVERSION.asType(type);
        MethodHandle last = identity;
        for(int i = factories.length; i-- > 0;) {
            final GuardedInvocation next = factories[i].convertToType(sourceType, targetType);
            if(next != null) {
                next.assertType(type);
                if(next.getGuard() == null) {
                    // If a converter is unconditional, choose it as the only converter
                    return next.getInvocation();
                }
                last = MethodHandles.guardWithTest(next.getGuard(), next.getInvocation(), last);
            }
        }
        return last == identity ? IDENTITY_CONVERSION : last;
    }

    private static final MethodHandle IDENTITY_CONVERSION = new Lookup(MethodHandles.lookup()).findStatic(
            TypeConverterFactory.class, "_identityConversion", MethodType.methodType(Object.class, Object.class));

    /**
     * This method is public for implementation reasons. Do not invoke it directly. Returns the object passed in.
     *
     * @param o the object
{'fraction_non_alphanumeric': 0.08540275459098498, 'fraction_numerical': 0.0015651085141903172, 'mean_word_length': 2.8246209098164408, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2654445', 'n_tokens_mistral': 4833, 'n_tokens_neox': 4702, 'n_words': 1525}