This commit is contained in:
Eric Maupin 2018-03-26 15:17:07 -04:00
Родитель bcbd312539
Коммит 12145ecc6b
2 изменённых файлов: 51 добавлений и 130 удалений

Просмотреть файл

@ -1,6 +1,6 @@
using System;
using System.ComponentModel;
using System.Reflection.Emit;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace Xamarin.PropertyEditing
@ -28,6 +28,17 @@ namespace Xamarin.PropertyEditing
private static Func<T, T> IncrementValue, DecrementValue;
private static NullableConverter NullConverter;
private static Func<T, T> GetNullableVersion (Expression shiftExpression, Type realType)
{
var v = Expression.Parameter (typeof(T));
var convert = Expression.Call (Expression.Constant (NullConverter), nameof(NullableConverter.ConvertFrom), null, Expression.Convert (v, typeof(object)));
var shift = Expression.Invoke (shiftExpression, Expression.Convert (convert, realType));
var conditional = Expression.Condition (Expression.Equal (v, Expression.Constant (null)), Expression.Default (realType), shift);
// (T v) => (T)((v == null) ? default(realType) : shiftExpression ((realType)NullableConverter.ConvertFrom ((object)v));
return Expression.Lambda<Func<T, T>> (Expression.Convert (conditional, typeof(T)), v).Compile();
}
private static void SetupMath ()
{
if (IncrementValue != null)
@ -40,110 +51,41 @@ namespace Xamarin.PropertyEditing
t = Nullable.GetUnderlyingType (t);
}
Task<Func<T, T>> createIncrement = Task.Run (() => {
var add = new DynamicMethod ("Add", t, new[] { t });
ILGenerator gen = add.GetILGenerator ();
gen.Emit (OpCodes.Ldarg_0);
Task<Func<T,T>> createIncrement = Task.Run (() => {
var value = Expression.Parameter (t);
switch (Type.GetTypeCode (t)) {
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
gen.Emit (OpCodes.Ldc_I4_1);
gen.Emit (OpCodes.Add_Ovf_Un);
break;
case TypeCode.UInt64:
gen.Emit (OpCodes.Ldc_I8, 1L);
gen.Emit (OpCodes.Add_Ovf_Un);
break;
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
gen.Emit (OpCodes.Ldc_I4_1);
gen.Emit (OpCodes.Add_Ovf);
break;
case TypeCode.Int64:
gen.Emit (OpCodes.Ldc_I8, 1L);
gen.Emit (OpCodes.Add_Ovf);
break;
case TypeCode.Single:
gen.Emit (OpCodes.Ldc_R4, 1f);
gen.Emit (OpCodes.Add);
break;
case TypeCode.Double:
gen.Emit (OpCodes.Ldc_R8, 1d);
gen.Emit (OpCodes.Add);
break;
default:
throw new NotSupportedException();
Expression add;
if (t == typeof(byte) || t == typeof(sbyte)) {
// (t value) => (t)((int)value + 1);
add = Expression.Convert (Expression.Add (Expression.Convert (value, typeof(int)), Expression.Constant (1)), t);
} else {
var shiftby = Expression.Convert (Expression.Constant (1), t);
add = Expression.Add (value, shiftby);
}
gen.Emit (OpCodes.Ret);
if (!isNullable)
return (Func<T,T>)add.CreateDelegate (typeof(Func<T, T>));
else {
Delegate a = add.CreateDelegate (typeof(Func<,>).MakeGenericType (new[] { t, t }));
return (v) => {
if (v == null)
return (T)Activator.CreateInstance (t);
else {
return (T)a.DynamicInvoke (NullConverter.ConvertFrom (v));
}
};
}
var increment = Expression.Lambda (add, value);
if (isNullable)
return GetNullableVersion (increment, t);
return (Func<T, T>)increment.Compile();
});
Task<Func<T, T>> createDecrement = Task.Run (() => {
var sub = new DynamicMethod ("Sub", t, new[] { t });
ILGenerator gen = sub.GetILGenerator ();
gen.Emit (OpCodes.Ldarg_0);
Task<Func<T,T>> createDecrement = Task.Run (() => {
var shiftby = Expression.Convert (Expression.Constant (1), t);
var value = Expression.Parameter (t);
switch (Type.GetTypeCode (t)) {
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
gen.Emit (OpCodes.Ldc_I4_1);
gen.Emit (OpCodes.Sub_Ovf_Un);
break;
case TypeCode.UInt64:
gen.Emit (OpCodes.Ldc_I8, 1L);
gen.Emit (OpCodes.Sub_Ovf_Un);
break;
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
gen.Emit (OpCodes.Ldc_I4_1);
gen.Emit (OpCodes.Sub_Ovf);
break;
case TypeCode.Int64:
gen.Emit (OpCodes.Ldc_I8, 1L);
gen.Emit (OpCodes.Sub_Ovf);
break;
case TypeCode.Single:
gen.Emit (OpCodes.Ldc_R4, 1f);
gen.Emit (OpCodes.Sub);
break;
case TypeCode.Double:
gen.Emit (OpCodes.Ldc_R8, 1d);
gen.Emit (OpCodes.Sub);
break;
default:
throw new NotSupportedException();
Expression sub;
if (t == typeof(byte) || t == typeof(sbyte)) {
sub = Expression.Convert (Expression.Subtract (Expression.Convert (value, typeof(int)), Expression.Constant (1)), t);
} else {
sub = Expression.Subtract (value, shiftby);
}
gen.Emit (OpCodes.Ret);
if (!isNullable)
return (Func<T,T>)sub.CreateDelegate (typeof(Func<T, T>));
else {
Delegate s = sub.CreateDelegate (typeof(Func<,>).MakeGenericType (t, t));
return (v) => {
if (v == null)
return (T)Activator.CreateInstance (t);
else {
return (T)s.DynamicInvoke (NullConverter.ConvertFrom (v));
}
};
}
var decrement = Expression.Lambda (sub, value);
if (isNullable)
return GetNullableVersion (decrement, t);
return (Func<T, T>)decrement.Compile();
});
IncrementValue = createIncrement.Result;

Просмотреть файл

@ -1,9 +1,9 @@
using System;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading.Tasks;
namespace Xamarin.PropertyEditing.Reflection
@ -131,12 +131,8 @@ namespace Xamarin.PropertyEditing.Reflection
{
return Casters.GetOrAdd (typeof(T), t => {
return Task.Run (() => {
DynamicMethod method = new DynamicMethod ("Caster", typeof(T), new[] { typeof(object) });
ILGenerator generator = method.GetILGenerator ();
generator.Emit (OpCodes.Ldarg_0);
generator.Emit (OpCodes.Castclass, typeof(T));
generator.Emit (OpCodes.Ret);
return method.CreateDelegate (typeof(Func<object, T>));
var arg = Expression.Parameter (typeof(object));
return Expression.Lambda (Expression.Convert (arg, typeof(T)), arg).Compile ();
});
});
}
@ -145,24 +141,10 @@ namespace Xamarin.PropertyEditing.Reflection
{
return HasFlagsMethods.GetOrAdd (typeof(T), t => {
return Task.Run (() => {
DynamicMethod method = new DynamicMethod ("HasFlags", typeof(bool), new[] { typeof(T), typeof(T) });
ILGenerator generator = method.GetILGenerator ();
generator.Emit (OpCodes.Ldarg_0);
generator.Emit (OpCodes.Ldarg_1);
generator.Emit (OpCodes.And); // arg0 & arg1
generator.Emit (OpCodes.Ldc_I4_0);
if (typeof (T) == typeof (uint))
generator.Emit (OpCodes.Conv_U4);
else if (typeof (T) == typeof (long))
generator.Emit (OpCodes.Conv_I8);
else if (typeof (T) == typeof (ulong))
generator.Emit (OpCodes.Conv_U8);
generator.Emit (OpCodes.Ceq); // pushes 1 if not equal
generator.Emit (OpCodes.Ldc_I4_0);
generator.Emit (OpCodes.Ceq); // reverses
generator.Emit (OpCodes.Ret);
return method.CreateDelegate (typeof(Func<T, T, bool>));
var left = Expression.Parameter (typeof(T));
var right = Expression.Parameter (typeof(T));
var hasFlag = Expression.Equal (Expression.And (left, right), right);
return Expression.Lambda (hasFlag, left, right).Compile();
});
});
}
@ -171,13 +153,10 @@ namespace Xamarin.PropertyEditing.Reflection
{
return OrOperators.GetOrAdd (typeof(T), t => {
return Task.Run (() => {
DynamicMethod method = new DynamicMethod ("Or", typeof(T), new[] { typeof(T), typeof(T) });
ILGenerator generator = method.GetILGenerator ();
generator.Emit (OpCodes.Ldarg_0);
generator.Emit (OpCodes.Ldarg_1);
generator.Emit (OpCodes.Or);
generator.Emit (OpCodes.Ret);
return method.CreateDelegate (typeof(Func<T, T, T>));
var left = Expression.Parameter (typeof(T));
var right = Expression.Parameter (typeof(T));
var or = Expression.Or (left, right);
return Expression.Lambda (or, left, right).Compile ();
});
});
}