<commit_before>﻿using System;
using System.Collections.Generic;
using System.Reflection;

using ZScript.Elements;
using ZScript.Runtime.Execution.Wrappers.Callables;
using ZScript.Runtime.Execution.Wrappers.Members;

namespace ZScript.Runtime.Execution.Wrappers
{
    /// <summary>
    /// Helper class used during member wrapping
    /// </summary>
    public static class MemberWrapperHelper
    {
        /// <summary>
        /// Returns an IMemberWrapper for a given target object's member.
        /// If the target object does not contains a matching field and it is not a ZObject instance, an ArgumentException is raised
        /// </summary>
        /// <param name="target">The target to wrap</param>
        /// <param name="memberName">The name of the member to wrap</param>
        /// <returns>An IMemberWrapper created from the given target</returns>
        /// <exception cref="ArgumentException">No member with the given name found on target object</exception>
        public static IMemberWrapper CreateMemberWrapper(object target, string memberName)
        {
            var z = target as ZObject;
            if (z != null)
            {
                return new ZObjectMember(z, memberName);
            }

            return ClassMember.CreateMemberWrapper(target, memberName);
        }

        /// <summary>
        /// Returns an ICallableWrapper for a given target object's method.
        /// If the target object does not contains a matching method, an ArgumentException is raised
        /// </summary>
        /// <param name="target">The target to wrap</param>
        /// <param name="callableName">The name of the method to wrap</param>
        /// <returns>An ICallableWrapper created from the given target</returns>
        /// <exception cref="ArgumentException">No method with the given name found on target object</exception>
        public static ICallableWrapper CreateCallableWrapper(object target, string callableName)
        {
            // Native method
            var methods = MethodsNamedFor(target.GetType(), callableName);

            if (methods.Length == 0)
                throw new ArgumentException("No public method of name '" + callableName + "' found on object of type '" + target.GetType() + "'", "callableName");

            return new ClassMethod(target, methods);
        }

        /// <summary>
        /// Gets all methods available for a given type
        /// </summary>
        /// <param name="type">The type to get the methods of</param>
        /// <returns>An array containing all of the methods for the given type</returns>
        private static MethodInfo[] MethodsForType(Type type)
        {
            MethodInfo[] o;
            if (TypeMethods.TryGetValue(type, out o))
            {
                return o;
            }

            return TypeMethods[type] = type.GetMethods();
        }

        /// <summary>
        /// Gets all methods on a given type that match the provided name
        /// </summary>
        /// <param name="type">The type to get the methods of</param>
        /// <param name="methodName">The name of the methods to match</param>
        /// <returns>An array containing all of the methods for the given type</returns>
        private static MethodInfo[] MethodsNamedFor(Type type, string methodName)
        {
            List<TypeMethodsNamed> cachedMethods;
            if (!CachedTypeMethodsNamed.TryGetValue(type, out cachedMethods))
            {
                cachedMethods = CachedTypeMethodsNamed[type] = new List<TypeMethodsNamed>();
            }

            for (int i = 0; i < cachedMethods.Count; i++)
            {
                if (cachedMethods[i].MethodName == methodName)
                    return cachedMethods[i].Methods;
            }

            // Add a new entry to the method cache list
            var methods = MethodsForType(type);
            var methodsNamed = new List<MethodInfo>();

            foreach (var method in methods)
            {
                if (method.Name == methodName)
                    methodsNamed.Add(method);
            }

            var cached = new TypeMethodsNamed(type, methodsNamed.ToArray(), methodName);

            cachedMethods.Add(cached);

            return cached.Methods;
        }

        /// <summary>
        /// Internal dictionary used to improve performance of the CreateCallableWrapper method
        /// </summary>
        private static readonly Dictionary<Type, MethodInfo[]> TypeMethods = new Dictionary<Type, MethodInfo[]>();

        /// <summary>
        /// Internal dictionary used to improve performance of the CreateCallableWrapper method
        /// </summary>
        private static readonly Dictionary<Type, List<TypeMethodsNamed>> CachedTypeMethodsNamed = new Dictionary<Type, List<TypeMethodsNamed>>();

        /// <summary>
        /// Struct that is used to cache lookups of type methods by name
        /// </summary>
        private struct TypeMethodsNamed
        {
            /// <summary>
            /// Gets the type associated with this TypeMethodsNamed struct
            /// </summary>
            public readonly Type Type;

            /// <summary>
            /// Gets the methods associated with this TypeMethodsNamed struct
            /// </summary>
            public readonly MethodInfo[] Methods;

            /// <summary>
            /// Gets the method names associated with this TypeMethodsNamed struct
            /// </summary>
            public readonly string MethodName;

            /// <summary>
            /// Initializes a new TypeMethodsNamed struct
            /// </summary>
            /// <param name="type">The type to assicate with this struct</param>
            /// <param name="methods">The array of matching methods to associate with this struct</param>
            /// <param name="methodName">The name of the method group</param>
            public TypeMethodsNamed(Type type, MethodInfo[] methods, string methodName)
            {
                Type = type;
                Methods = methods;
                MethodName = methodName;
            }
        }
    }
}<commit_msg>Removing type field from MemberWrapperHelper.TypeMethodsNamed struct<commit_after>﻿using System;
using System.Collections.Generic;
using System.Reflection;

using ZScript.Elements;
using ZScript.Runtime.Execution.Wrappers.Callables;
using ZScript.Runtime.Execution.Wrappers.Members;

namespace ZScript.Runtime.Execution.Wrappers
{
    /// <summary>
    /// Helper class used during member wrapping
    /// </summary>
    public static class MemberWrapperHelper
    {
        /// <summary>
        /// Returns an IMemberWrapper for a given target object's member.
        /// If the target object does not contains a matching field and it is not a ZObject instance, an ArgumentException is raised
        /// </summary>
        /// <param name="target">The target to wrap</param>
        /// <param name="memberName">The name of the member to wrap</param>
        /// <returns>An IMemberWrapper created from the given target</returns>
        /// <exception cref="ArgumentException">No member with the given name found on target object</exception>
        public static IMemberWrapper CreateMemberWrapper(object target, string memberName)
        {
            var z = target as ZObject;
            if (z != null)
            {
                return new ZObjectMember(z, memberName);
            }

            return ClassMember.CreateMemberWrapper(target, memberName);
        }

        /// <summary>
        /// Returns an ICallableWrapper for a given target object's method.
        /// If the target object does not contains a matching method, an ArgumentException is raised
        /// </summary>
        /// <param name="target">The target to wrap</param>
        /// <param name="callableName">The name of the method to wrap</param>
        /// <returns>An ICallableWrapper created from the given target</returns>
        /// <exception cref="ArgumentException">No method with the given name found on target object</exception>
        public static ICallableWrapper CreateCallableWrapper(object target, string callableName)
        {
            // Native method
            var methods = MethodsNamedFor(target.GetType(), callableName);

            if (methods.Length == 0)
                throw new ArgumentException("No public method of name '" + callableName + "' found on object of type '" + target.GetType() + "'", "callableName");

            return new ClassMethod(target, methods);
        }

        /// <summary>
        /// Gets all methods available for a given type
        /// </summary>
        /// <param name="type">The type to get the methods of</param>
        /// <returns>An array containing all of the methods for the given type</returns>
        private static MethodInfo[] MethodsForType(Type type)
        {
            MethodInfo[] o;
            if (TypeMethods.TryGetValue(type, out o))
            {
                return o;
            }

            return TypeMethods[type] = type.GetMethods();
        }

        /// <summary>
        /// Gets all methods on a given type that match the provided name
        /// </summary>
        /// <param name="type">The type to get the methods of</param>
        /// <param name="methodName">The name of the methods to match</param>
        /// <returns>An array containing all of the methods for the given type</returns>
        private static MethodInfo[] MethodsNamedFor(Type type, string methodName)
        {
            List<TypeMethodsNamed> cachedMethods;
            if (!CachedTypeMethodsNamed.TryGetValue(type, out cachedMethods))
            {
                cachedMethods = CachedTypeMethodsNamed[type] = new List<TypeMethodsNamed>();
            }

            for (int i = 0; i < cachedMethods.Count; i++)
            {
                if (cachedMethods[i].MethodName == methodName)
                    return cachedMethods[i].Methods;
            }

            // Add a new entry to the method cache list
            var methods = MethodsForType(type);
            var methodsNamed = new List<MethodInfo>();

            foreach (var method in methods)
            {
                if (method.Name == methodName)
                    methodsNamed.Add(method);
            }

            var cached = new TypeMethodsNamed(methodsNamed.ToArray(), methodName);

            cachedMethods.Add(cached);

            return cached.Methods;
        }

        /// <summary>
        /// Internal dictionary used to improve performance of the CreateCallableWrapper method
        /// </summary>
        private static readonly Dictionary<Type, MethodInfo[]> TypeMethods = new Dictionary<Type, MethodInfo[]>();

        /// <summary>
        /// Internal dictionary used to improve performance of the CreateCallableWrapper method
        /// </summary>
        private static readonly Dictionary<Type, List<TypeMethodsNamed>> CachedTypeMethodsNamed = new Dictionary<Type, List<TypeMethodsNamed>>();

        /// <summary>
        /// Struct that is used to cache lookups of type methods by name
        /// </summary>
        private struct TypeMethodsNamed
        {
            /// <summary>
            /// Gets the methods associated with this TypeMethodsNamed struct
            /// </summary>
            public readonly MethodInfo[] Methods;

            /// <summary>
            /// Gets the method names associated with this TypeMethodsNamed struct
            /// </summary>
            public readonly string MethodName;

            /// <summary>
            /// Initializes a new TypeMethodsNamed struct
            /// </summary>
            /// <param name="methods">The array of matching methods to associate with this struct</param>
            /// <param name="methodName">The name of the method group</param>
            public TypeMethodsNamed(MethodInfo[] methods, string methodName)
            {
                Methods = methods;
                MethodName = methodName;
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.09791425260718424, 'fraction_numerical': 0.00033107101473266014, 'mean_word_length': 1.9615196078431372, 'pattern_counts': {'":': 0, '<': 131, '<?xml version=': 0, '>': 129, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7056407', 'n_tokens_mistral': 2826, 'n_tokens_neox': 2746, 'n_words': 976}