/// <summary> /// Two special cases for the right-hand side of an assignment or argument to a new expression where it turns into a column swing: /// g = e_i.f /// Then the projection for g turns into a swing of the column from f /// E_i must be a decomposable type /// g = e_i /// The the projection for g turns into a swing of the pseudo-column for E_i /// E_i must be an atomic type /// </summary> /// <returns>True iff the expression was transformed, either into a computed field or a swinging field.</returns> private bool HandleSimpleAssignments(Expression e, MyFieldInfo destinationColumn) { var simpleAssignedValue = e as MemberExpression; ParameterExpression parameter = null; if (simpleAssignedValue != null) { parameter = simpleAssignedValue.Expression as ParameterExpression; } var paramIsForThisLambda = parameter != null && this.parameterInformation.ContainsKey(parameter); if (simpleAssignedValue != null && paramIsForThisLambda) { if (!this.parameterInformation.TryGetValue(parameter, out SelectParameterInformation spi)) { // if this particular parameter is not being substituted for, then the caller must not want it turned // into anything. however, i think it might be an error situation and "this.error" should be set to true. this.computedFields.Add(destinationColumn, simpleAssignedValue); return(true); } var columnarField = spi.parameterRepresentation.Fields[simpleAssignedValue.Member.Name]; if (this.noSwingingFields) { var a = GetBatchColumnIndexer(parameter, columnarField); this.computedFields.Add(destinationColumn, a); } else { this.swingingFields.Add(Tuple.Create(destinationColumn, columnarField)); } return(true); } parameter = e as ParameterExpression; if (parameter != null && this.parameterInformation.ContainsKey(parameter)) { if (this.parameterInformation.TryGetValue(parameter, out SelectParameterInformation spi)) { var cr = spi.parameterRepresentation; if (!cr.noFields) { this.error = true; return(false); } if (this.noSwingingFields) { var a = GetBatchColumnIndexer(parameter, cr.PseudoField); this.computedFields.Add(destinationColumn, a); } else { this.swingingFields.Add(Tuple.Create(destinationColumn, cr.PseudoField)); } return(true); } } return(false); }
protected static string ColumnPointerFieldAssignment(MyFieldInfo f, string batchName) { if (f.OptimizeString()) { return(string.Format("this.{1}_{0}_col = {1}.{0};", f.Name, batchName)); } else { return(string.Format("this.{1}_{0}_col = {1}.{0}.col;", f.Name, batchName)); } }
protected static string ColumnPointerFieldDeclaration(MyFieldInfo f, string batchName) { if (f.OptimizeString()) { return(string.Format("Microsoft.StreamProcessing.Internal.Collections.Multistring {1}_{0}_col;", f.Name, batchName)); } else { return(string.Format("{2} {1}_{0}_col;", f.Name, batchName, f.Type.MakeArrayType().GetCSharpSourceSyntax())); } }
protected static string EndColumnPointerDeclaration(MyFieldInfo f) { if (f.canBeFixed) { return("}"); } else { return(string.Empty); } }
public ColumnarRepresentation(Type t) { this.RepresentationFor = t; var d = new Dictionary <string, MyFieldInfo>(); this.Fields = d; foreach (var f in t.GetTypeInfo().GetFields(BindingFlags.Instance | BindingFlags.Public)) { d.Add(f.Name, new MyFieldInfo(f /*, prefix*/)); } // Any autoprops should be treated just as if they were a field foreach (var p in t.GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { var getMethod = p.GetMethod; if (getMethod == null) { continue; } if (!getMethod.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))) { continue; } var setMethod = p.SetMethod; if (setMethod == null) { continue; } if (!setMethod.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))) { continue; } d.Add(p.Name, new MyFieldInfo(p /*, prefix*/)); } if (!this.Fields.Any()) { if (t.HasSupportedParameterizedConstructor()) { foreach (var p in t.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { d.Add(p.Name, new MyFieldInfo(p /*, prefix*/)); } } else { this.noFields = true; this.PseudoField = new MyFieldInfo(t, "payload"); } } }
protected static string BeginColumnPointerDeclaration(MyFieldInfo f, string batchName) { if (f.canBeFixed) { return(string.Format("fixed ({0}* {2}_{1}_col = {2}.{1}.col) {{", f.TypeName, f.Name, batchName)); } else if (f.OptimizeString()) { return(string.Format("var {1}_{0}_col = {1}.{0};", f.Name, batchName)); } else { return(string.Format("var {1}_{0}_col = {1}.{0}.col;", f.Name, batchName)); } }
private IndexExpression GetBatchColumnIndexer(ParameterExpression parameter, MyFieldInfo f) { Contract.Requires(this.parameterInformation.ContainsKey(parameter)); var parameterInfo = this.parameterInformation[parameter]; var batch = Expression.Variable(parameterInfo.BatchType, parameterInfo.BatchName); var column = Expression.Field(batch, f.Name); var indexVariable = Expression.Variable(typeof(int), parameterInfo.IndexVariableName); if (column.Type.Equals(typeof(Internal.Collections.MultiString))) { var indexer = typeof(Internal.Collections.MultiString).GetTypeInfo().GetProperty("Item"); return(Expression.MakeIndex(column, indexer, new List <Expression>() { indexVariable })); } else { var colArray = Expression.Field(column, "col"); return(Expression.ArrayAccess(colArray, indexVariable)); } }
public static Tuple <Type, string> Generate <TOuterKey, TSource, TInnerKey>( Expression <Func <TInnerKey, int> > hashComparer, Expression <Func <TSource, TInnerKey> > keySelector, bool nested) { var typeOfTOuterKey = typeof(TOuterKey); var typeOfTSource = typeof(TSource); var typeOfTInnerKey = typeof(TInnerKey); string expandedCode; List <Assembly> assemblyReferences; string errorMessages = null; try { string generatedClassName = $"GeneratedGroupStreamable_{GroupStreamableSequenceNumber++}"; string transformedKeySelectorAsString; MyFieldInfo swingingField = default; if (typeOfTInnerKey.IsAnonymousTypeName()) { Contract.Assume(keySelector.Body is NewExpression); var transformedFunction = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector); var newBody = (NewExpression)transformedFunction.Body; transformedKeySelectorAsString = string.Join(",", newBody.Arguments.Select(arg => arg.ExpressionToCSharp())); } else { var body = keySelector.Body; if (!nested && body is MemberExpression singleFieldProjection) { if (singleFieldProjection.Expression is ParameterExpression dereferencedObject) { // then can just swing a pointer to set the key of the result message Contract.Assume(dereferencedObject == keySelector.Parameters.ElementAt(0)); var f = singleFieldProjection.Member; var sourceMessageRepresentation = new ColumnarRepresentation(typeOfTSource); var fieldToSwingFrom = sourceMessageRepresentation.Fields[f.Name]; swingingField = fieldToSwingFrom; transformedKeySelectorAsString = swingingField.Name + "_col[i]"; } else { var transformedPredicate = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector).Body; if (transformedPredicate == null) { return(Tuple.Create((Type)null, errorMessages)); } transformedKeySelectorAsString = transformedPredicate.ExpressionToCSharp(); } } else { var transformedPredicate = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector).Body; if (transformedPredicate == null) { return(Tuple.Create((Type)null, errorMessages)); } transformedKeySelectorAsString = transformedPredicate.ExpressionToCSharp(); } } var inlinedHashCodeComputation = hashComparer.Inline("key"); var template = new GroupTemplate( generatedClassName, typeOfTOuterKey, typeOfTSource, typeOfTInnerKey, transformedKeySelectorAsString, inlinedHashCodeComputation, nested) { swingingField = swingingField, payloadMightBeNull = typeOfTSource.CanContainNull() }; if (!nested && Config.UseMultiString && typeOfTInnerKey.Equals(typeof(string)) && keySelector.IsSimpleFieldOrPropertyAccess()) { var transformedPredicate = Extensions.TransformUnaryFunction <TOuterKey, TSource>(keySelector).Body; template.transformedKeySelectorAsString = transformedPredicate.ExpressionToCSharp(); template.inlinedHashCodeComputation = "hashCodeVector.col[i]"; var fieldName = ((MemberExpression)keySelector.Body).Member.Name; template.vectorHashCodeInitialization = $"resultBatch.hash = {Transformer.ColumnFieldPrefix}{fieldName}_col.GetHashCode(batch.bitvector);"; template.swingingHashColumn = true; } template.fields = new ColumnarRepresentation(typeOfTSource).AllFields; expandedCode = template.TransformText(); assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey); assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly); assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TOuterKey, TSource>()); if (nested) { assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <CompoundGroupKey <TOuterKey, TInnerKey>, TSource>()); assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <CompoundGroupKey <TOuterKey, TInnerKey>, TSource>()); } else { assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TInnerKey, TSource>()); assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TInnerKey, TSource>()); } assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(keySelector)); var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages); if (typeOfTInnerKey.IsAnonymousTypeName()) { if (errorMessages == null) { errorMessages = string.Empty; } errorMessages += "\nCodegen Warning: The inner key type for Group is anonymous, causing the use of Activator.CreateInstance in an inner loop. This will lead to poor performance.\n"; } generatedClassName = generatedClassName.AddNumberOfNecessaryGenericArguments(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey); var t = a.GetType(generatedClassName); t = t.InstantiateAsNecessary(typeOfTOuterKey, typeOfTSource, typeOfTInnerKey); return(Tuple.Create(t, errorMessages)); } catch { if (Config.CodegenOptions.DontFallBackToRowBasedExecution) { throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!"); } return(Tuple.Create((Type)null, errorMessages)); } }
public static bool OptimizeString(this MyFieldInfo field) => Config.UseMultiString && field.Type == typeof(string);
public static string AccessExpressionForRowValue(this MyFieldInfo f, string batchVariableName, string indexVariableName) => string.Format(CultureInfo.InvariantCulture, "{0}.{1}{2}[{3}]", batchVariableName, f.Name, f.OptimizeString() ? string.Empty : ".col", indexVariableName);
public ColumnarRepresentation(Type t, string pseudoFieldName) { this.RepresentationFor = t; this.noFields = true; this.PseudoField = new MyFieldInfo(t, pseudoFieldName); }
protected static string ColumnPointerFieldAssignment(MyFieldInfo f, string batchName) => f.OptimizeString() ? string.Format("this.{1}_{0}_col = {1}.{0};", f.Name, batchName) : string.Format("this.{1}_{0}_col = {1}.{0}.col;", f.Name, batchName);
protected static string EndColumnPointerDeclaration(MyFieldInfo f) => f.canBeFixed ? "}" : string.Empty;
protected static string BeginColumnPointerDeclaration(MyFieldInfo f, string batchName) => f.canBeFixed ? string.Format("fixed ({0}* {2}_{1}_col = {2}.{1}.col) {{", f.TypeName, f.Name, batchName) : f.OptimizeString() ? string.Format("var {1}_{0}_col = {1}.{0};", f.Name, batchName) : string.Format("var {1}_{0}_col = {1}.{0}.col;", f.Name, batchName);