File: System\Linq\Expressions\Interpreter\Utilities.cs
Web Access
Project: src\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic.Utils;
using System.Reflection;
using System.Runtime.ExceptionServices;
 
namespace System.Linq.Expressions.Interpreter
{
#if FEATURE_MAKE_RUN_METHODS
    internal static partial class DelegateHelpers
    {
        private const int MaximumArity = 17;
 
        internal static Type MakeDelegate(Type[] types)
        {
            Debug.Assert(types != null && types.Length > 0);
 
            // Can only used predefined delegates if we have no byref types and
            // the arity is small enough to fit in Func<...> or Action<...>
            if (types.Length > MaximumArity || types.Any(t => t.IsByRef))
            {
                throw ContractUtils.Unreachable;
            }
 
            Type returnType = types[types.Length - 1];
            if (returnType == typeof(void))
            {
                Array.Resize(ref types, types.Length - 1);
                switch (types.Length)
                {
                    case 0: return typeof(Action);
 
                    case 1: return typeof(Action<>).MakeGenericType(types);
                    case 2: return typeof(Action<,>).MakeGenericType(types);
                    case 3: return typeof(Action<,,>).MakeGenericType(types);
                    case 4: return typeof(Action<,,,>).MakeGenericType(types);
                    case 5: return typeof(Action<,,,,>).MakeGenericType(types);
                    case 6: return typeof(Action<,,,,,>).MakeGenericType(types);
                    case 7: return typeof(Action<,,,,,,>).MakeGenericType(types);
                    case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types);
                    case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types);
                    case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types);
                    case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types);
                    case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types);
                    case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types);
                    case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types);
                    case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types);
                    case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types);
                }
            }
            else
            {
                switch (types.Length)
                {
                    case 1: return typeof(Func<>).MakeGenericType(types);
                    case 2: return typeof(Func<,>).MakeGenericType(types);
                    case 3: return typeof(Func<,,>).MakeGenericType(types);
                    case 4: return typeof(Func<,,,>).MakeGenericType(types);
                    case 5: return typeof(Func<,,,,>).MakeGenericType(types);
                    case 6: return typeof(Func<,,,,,>).MakeGenericType(types);
                    case 7: return typeof(Func<,,,,,,>).MakeGenericType(types);
                    case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);
                    case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);
                    case 10: return typeof(Func<,,,,,,,,,>).MakeGenericType(types);
                    case 11: return typeof(Func<,,,,,,,,,,>).MakeGenericType(types);
                    case 12: return typeof(Func<,,,,,,,,,,,>).MakeGenericType(types);
                    case 13: return typeof(Func<,,,,,,,,,,,,>).MakeGenericType(types);
                    case 14: return typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(types);
                    case 15: return typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(types);
                    case 16: return typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(types);
                    case 17: return typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(types);
                }
            }
            throw ContractUtils.Unreachable;
        }
    }
#endif
 
    internal static class ScriptingRuntimeHelpers
    {
        public static object Int32ToObject(int i) =>
            i switch
            {
                -1 => Utils.BoxedIntM1,
                0 => Utils.BoxedInt0,
                1 => Utils.BoxedInt1,
                2 => Utils.BoxedInt2,
                3 => Utils.BoxedInt3,
 
                _ => i,
            };
 
        internal static object? GetPrimitiveDefaultValue(Type type)
        {
            object result;
 
            switch (type.GetTypeCode())
            {
                case TypeCode.Boolean:
                    result = Utils.BoxedFalse;
                    break;
                case TypeCode.SByte:
                    result = Utils.BoxedDefaultSByte;
                    break;
                case TypeCode.Byte:
                    result = Utils.BoxedDefaultByte;
                    break;
                case TypeCode.Char:
                    result = Utils.BoxedDefaultChar;
                    break;
                case TypeCode.Int16:
                    result = Utils.BoxedDefaultInt16;
                    break;
                case TypeCode.Int32:
                    result = Utils.BoxedInt0;
                    break;
                case TypeCode.Int64:
                    result = Utils.BoxedDefaultInt64;
                    break;
                case TypeCode.UInt16:
                    result = Utils.BoxedDefaultUInt16;
                    break;
                case TypeCode.UInt32:
                    result = Utils.BoxedDefaultUInt32;
                    break;
                case TypeCode.UInt64:
                    result = Utils.BoxedDefaultUInt64;
                    break;
                case TypeCode.Single:
                    return Utils.BoxedDefaultSingle;
                case TypeCode.Double:
                    return Utils.BoxedDefaultDouble;
                case TypeCode.DateTime:
                    return Utils.BoxedDefaultDateTime;
                case TypeCode.Decimal:
                    return Utils.BoxedDefaultDecimal;
                default:
                    // Also covers DBNull which is a class.
                    return null;
            }
 
            if (type.IsEnum)
            {
                result = Enum.ToObject(type, result);
            }
 
            return result;
        }
    }
 
    internal static class ExceptionHelpers
    {
        /// <summary>
        /// Updates an exception before it's getting re-thrown so
        /// we can present a reasonable stack trace to the user.
        /// </summary>
        public static void UnwrapAndRethrow(TargetInvocationException exception)
        {
            ExceptionDispatchInfo.Throw(exception.InnerException!);
        }
    }
 
    /// <summary>
    /// A hybrid dictionary which compares based upon object identity.
    /// </summary>
    internal sealed class HybridReferenceDictionary<TKey, TValue> where TKey : class
    {
        private KeyValuePair<TKey, TValue>[]? _keysAndValues;
        private Dictionary<TKey, TValue>? _dict;
        private const int ArraySize = 10;
 
        public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
        {
            Debug.Assert(key != null);
 
            if (_dict != null)
            {
                return _dict.TryGetValue(key, out value);
            }
            else if (_keysAndValues != null)
            {
                for (int i = 0; i < _keysAndValues.Length; i++)
                {
                    if (_keysAndValues[i].Key == key)
                    {
                        value = _keysAndValues[i].Value;
                        return true;
                    }
                }
            }
            value = default;
            return false;
        }
 
        public void Remove(TKey key)
        {
            Debug.Assert(key != null);
 
            if (_dict != null)
            {
                _dict.Remove(key);
            }
            else if (_keysAndValues != null)
            {
                for (int i = 0; i < _keysAndValues.Length; i++)
                {
                    if (_keysAndValues[i].Key == key)
                    {
                        _keysAndValues[i] = default;
                        return;
                    }
                }
            }
        }
 
        public bool ContainsKey(TKey key)
        {
            Debug.Assert(key != null);
 
            if (_dict != null)
            {
                return _dict.ContainsKey(key);
            }
 
            KeyValuePair<TKey, TValue>[]? keysAndValues = _keysAndValues;
            if (keysAndValues != null)
            {
                for (int i = 0; i < keysAndValues.Length; i++)
                {
                    if (keysAndValues[i].Key == key)
                    {
                        return true;
                    }
                }
            }
 
            return false;
        }
 
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            if (_dict != null)
            {
                return _dict.GetEnumerator();
            }
 
            return GetEnumeratorWorker();
        }
 
        private IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorWorker()
        {
            if (_keysAndValues != null)
            {
                for (int i = 0; i < _keysAndValues.Length; i++)
                {
                    if (_keysAndValues[i].Key != null)
                    {
                        yield return _keysAndValues[i];
                    }
                }
            }
        }
 
        public TValue this[TKey key]
        {
            get
            {
                Debug.Assert(key != null);
 
                TValue? res;
                if (TryGetValue(key, out res))
                {
                    return res;
                }
 
                throw new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString()));
            }
            set
            {
                Debug.Assert(key != null);
 
                if (_dict != null)
                {
                    _dict[key] = value;
                }
                else
                {
                    int index;
                    if (_keysAndValues != null)
                    {
                        index = -1;
                        for (int i = 0; i < _keysAndValues.Length; i++)
                        {
                            if (_keysAndValues[i].Key == key)
                            {
                                _keysAndValues[i] = new KeyValuePair<TKey, TValue>(key, value);
                                return;
                            }
                            else if (_keysAndValues[i].Key == null)
                            {
                                index = i;
                            }
                        }
                    }
                    else
                    {
                        _keysAndValues = new KeyValuePair<TKey, TValue>[ArraySize];
                        index = 0;
                    }
 
                    if (index != -1)
                    {
                        _keysAndValues[index] = new KeyValuePair<TKey, TValue>(key, value);
                    }
                    else
                    {
                        _dict = new Dictionary<TKey, TValue>();
                        for (int i = 0; i < _keysAndValues.Length; i++)
                        {
                            _dict[_keysAndValues[i].Key] = _keysAndValues[i].Value;
                        }
                        _keysAndValues = null;
 
                        _dict[key] = value;
                    }
                }
            }
        }
    }
 
    internal static class Assert
    {
        [Conditional("DEBUG")]
        public static void NotNull(object var)
        {
            Debug.Assert(var != null);
        }
    }
}