/// <summary> /// Returns true iff the equality and hashcode functions defined in /// <paramref name="payloadEqualityComparer"/> can be used in columnar codegen. /// </summary> /// <typeparam name="T">The type of the payload</typeparam> /// <param name="payloadEqualityComparer">The equality and hashcode functions /// represented as lambda expressions.</param> /// <returns>True iff both the equality and hashcode functions can be used in columnar /// codegen operators.</returns> public static bool CanUsePayloadEquality <T>(this IEqualityComparerExpression <T> payloadEqualityComparer) { var typeofT = typeof(T); // If T is a struct, then even if the user defined equality function calls a method on the struct, // it can still be used because the active events will have a field of type T. if (typeofT.GetTypeInfo().IsValueType) { return(true); } // If T is a type for which the columnar representation is just a pseudo-field, e.g., string, // then the payload is not really represented as a set of its fields, but is an instance of T if (new ColumnarRepresentation(typeofT).noFields) { return(true); } // If T is a reference type, then codegen is going to define a structurally-equivalent type T' // and the active events will have a field of type T'. So if the equality or hash functions ever // use a value of type T (other than to dereference it for a field/property) then it cannot be used. var equalsIsBad = ParameterInstanceFinder.FoundInstance(payloadEqualityComparer.GetEqualsExpr()); var hashIsBad = ParameterInstanceFinder.FoundInstance(payloadEqualityComparer.GetGetHashCodeExpr()); return(!equalsIsBad && !hashIsBad); }
public static IEqualityComparerExpression <T> GetCompoundEqualityComparerExpression <T, T1, T2, T3>(Expression <Func <T, T1> > lambda1, IEqualityComparerExpression <T1> iece1, Expression <Func <T, T2> > lambda2, IEqualityComparerExpression <T2> iece2, Expression <Func <T, T3> > lambda3, IEqualityComparerExpression <T3> iece3) { var iece1EqualsExpr = iece1.GetEqualsExpr(); var iece2EqualsExpr = iece2.GetEqualsExpr(); var iece3EqualsExpr = iece3.GetEqualsExpr(); Expression <Func <T, T, bool> > equalsTemplate = (left, right) => CallInliner.Call(iece1EqualsExpr, CallInliner.Call(lambda1, left), CallInliner.Call(lambda1, right)) && CallInliner.Call(iece2EqualsExpr, CallInliner.Call(lambda2, left), CallInliner.Call(lambda2, right)) && CallInliner.Call(iece3EqualsExpr, CallInliner.Call(lambda3, left), CallInliner.Call(lambda3, right)) ; var iece1HashExpr = iece1.GetGetHashCodeExpr(); var iece2HashExpr = iece2.GetGetHashCodeExpr(); var iece3HashExpr = iece3.GetGetHashCodeExpr(); Expression <Func <T, int> > hashTemplate = value => CallInliner.Call(iece1HashExpr, CallInliner.Call(lambda1, value)) ^ CallInliner.Call(iece2HashExpr, CallInliner.Call(lambda2, value)) ^ CallInliner.Call(iece3HashExpr, CallInliner.Call(lambda3, value)) ; return(new EqualityComparerExpression <T>(equalsTemplate.InlineCalls(), hashTemplate.InlineCalls())); }
public static Func <FastDictionary2 <TKey, TValue> > CreateFastDictionary2Generator <TKey, TValue>( this IEqualityComparerExpression <TKey> comparerExp, int capacity, Func <TKey, TKey, bool> equalsFunc, Func <TKey, int> getHashCodeFunc, QueryContainer container) { if (EqualityComparerExpression <TKey> .IsSimpleDefault(comparerExp)) { return(() => new FastDictionary2 <TKey, TValue>()); } if (container == null) { return(() => new FastDictionary2 <TKey, TValue>(capacity, equalsFunc, getHashCodeFunc)); } var equalsExp = comparerExp.GetEqualsExpr(); var getHashCodeExp = comparerExp.GetGetHashCodeExpr(); var vars = VariableFinder.Find(equalsExp).Select(o => o.GetHashCode()).ToList(); if (!vars.Any()) { vars.Add(string.Empty.StableHash()); } var hashvars = VariableFinder.Find(getHashCodeExp).Select(o => o.GetHashCode()).ToList(); if (!hashvars.Any()) { hashvars.Add(string.Empty.StableHash()); } var key = Tuple.Create( equalsExp.ToString() + getHashCodeExp.ToString() + string.Concat(vars.Aggregate((a, i) => a ^ i)) + string.Concat(hashvars.Aggregate((a, i) => a ^ i)), typeof(TKey), typeof(TValue)); Type temp; lock (sentinel) { if (!generatorCache.TryGetValue(key, out temp)) { string typeName = Prefix + classCounter++; var builderCode = new GeneratedFastDictionary(typeName, "2").TransformText(); var a = Transformer.CompileSourceCode(builderCode, Array.Empty <Assembly>(), out string errorMessages); temp = a.GetType(typeName + "`2"); temp = temp.MakeGenericType(typeof(TKey), typeof(TValue)); MethodInfo init = temp.GetTypeInfo().GetMethod("Initialize", BindingFlags.Static | BindingFlags.Public); init.Invoke(null, new object[] { equalsFunc, getHashCodeFunc, capacity }); generatorCache.Add(key, temp); } if (!container.TryGetFastDictionary2Type(key, out Type other)) { container.RegisterFastDictionary2Type(key, temp); } } return(() => (FastDictionary2 <TKey, TValue>)Activator.CreateInstance(temp)); }
public static IEqualityComparerExpression <T> GetEqualityComparerExpression <T, T1>( Expression <Func <T, T1> > lambda1, IEqualityComparerExpression <T1> iece1) { var iece1EqualsExpr = iece1.GetEqualsExpr(); Expression <Func <T, T, bool> > equalsTemplate = (left, right) => CallInliner.Call(iece1EqualsExpr, CallInliner.Call(lambda1, left), CallInliner.Call(lambda1, right)); var iece1HashExpr = iece1.GetGetHashCodeExpr(); Expression <Func <T, int> > hashTemplate = value => CallInliner.Call(iece1HashExpr, CallInliner.Call(lambda1, value)); return(new EqualityComparerExpression <T>(equalsTemplate.InlineCalls(), hashTemplate.InlineCalls())); }
public static bool ExpressionEquals <T>(this IEqualityComparerExpression <T> source, IEqualityComparerExpression <T> other) { return(EqualityComparer.IsEqual(source.GetEqualsExpr(), other.GetEqualsExpr()) && EqualityComparer.IsEqual(source.GetGetHashCodeExpr(), other.GetGetHashCodeExpr())); }
private static bool IsEqualIECE <T>(IEqualityComparerExpression <T> o1, IEqualityComparerExpression <T> o2) { return(EqualityComparer.IsEqual(o1.GetEqualsExpr(), o2.GetEqualsExpr()) && EqualityComparer.IsEqual(o1.GetGetHashCodeExpr(), o2.GetGetHashCodeExpr())); }