public TestAtomicModule(int inportCount, int outportCount) { var inports = Enumerable.Range(0, inportCount).Select(i => new Inlet <object>(".in" + i)).ToImmutableArray <Inlet>(); var outports = Enumerable.Range(0, outportCount).Select(i => new Outlet <object>(".out" + i)).ToImmutableArray <Outlet>(); Shape = new AmorphousShape(inports, outports); }
/// <summary> /// Transform a set of GraphStageModules into a single GraphModule. This is done /// by performing a traversal of all their Inlets, sorting them into those without /// internal connections(the exposed inlets) and those with internal connections /// (where the corresponding Outlet is recorded in a map so that it will be wired /// to the same slot number in the GraphAssembly). Then all Outlets are traversed, /// completing internal connections using the aforementioned maps and appending /// the others to the list of exposed Outlets. /// </summary> private static GraphModule FuseGroup(BuildStructuralInfo info, ISet <IModule> group) { var stages = new IGraphStageWithMaterializedValue <Shape, object> [group.Count]; var materializedValueIds = new IModule[group.Count]; var attributes = new Attributes[group.Count]; /* * The overall GraphAssembly arrays are constructed in three parts: * - 1) exposed inputs (ins) * - 2) connections (ins and outs) * - 3) exposed outputs (outs) */ var insB1 = new List <Inlet>(); var insB2 = new List <Inlet>(); var outsB3 = new List <Outlet>(); var inOwnersB1 = new List <int>(); var inOwnersB2 = new List <int>(); var outOwnersB3 = new List <int>(); // for the shape of the GraphModule var inlets = ImmutableArray.CreateBuilder <Inlet>(2); var outlets = ImmutableArray.CreateBuilder <Outlet>(2); // connection slots are allocated from the inputs side, outs find their place by this map var outConns = new Dictionary <OutPort, int>(); /* * First traverse all Inlets and sort them into exposed and internal, * taking note of their partner Outlets where appropriate. */ var pos = 0; var enumerator = group.GetEnumerator(); var ups = info.Upstreams; var downs = info.Downstreams; var outGroup = info.OutGroups; while (enumerator.MoveNext()) { CopiedModule copy; GraphStageModule graphStageModule; if ((copy = enumerator.Current as CopiedModule) != null && (graphStageModule = copy.CopyOf as GraphStageModule) != null) { stages[pos] = graphStageModule.Stage; materializedValueIds[pos] = copy; attributes[pos] = copy.Attributes.And(graphStageModule.Attributes); var copyInlets = copy.Shape.Inlets.GetEnumerator(); var originalInlets = graphStageModule.Shape.Inlets.GetEnumerator(); while (copyInlets.MoveNext() && originalInlets.MoveNext()) { var copyInlet = copyInlets.Current; var originalInlet = originalInlets.Current; var isInternal = ups.TryGetValue(copyInlet, out var outport) && outGroup.TryGetValue(outport, out var g) && g == group; if (isInternal) { ups.Remove(copyInlet); downs.Remove(outport); outConns[outport] = insB2.Count; insB2.Add(originalInlet); inOwnersB2.Add(pos); } else { insB1.Add(originalInlet); inOwnersB1.Add(pos); inlets.Add(copyInlet); } } pos++; } else { throw new ArgumentException("unexpected module structure"); } } var outsB2 = new Outlet[insB2.Count]; var outOwnersB2 = new int[insB2.Count]; /* * Then traverse all Outlets and complete connections. */ pos = 0; enumerator = group.GetEnumerator(); while (enumerator.MoveNext()) { CopiedModule copy; GraphStageModule graphStageModule; if ((copy = enumerator.Current as CopiedModule) != null && (graphStageModule = copy.CopyOf as GraphStageModule) != null) { var copyOutlets = copy.Shape.Outlets.GetEnumerator(); var originalOutlets = graphStageModule.Shape.Outlets.GetEnumerator(); while (copyOutlets.MoveNext() && originalOutlets.MoveNext()) { var copyOutlet = copyOutlets.Current; var originalOutlet = originalOutlets.Current; if (outConns.TryGetValue(copyOutlet, out int idx)) { outConns.Remove(copyOutlet); outsB2[idx] = originalOutlet; outOwnersB2[idx] = pos; } else { outsB3.Add(originalOutlet); outOwnersB3.Add(pos); outlets.Add(copyOutlet); } } pos++; } else { throw new ArgumentException("unexpected module structure"); } } /* * Now mechanically gather together the GraphAssembly arrays from their various pieces. */ var shape = new AmorphousShape(inlets.ToImmutable(), outlets.ToImmutable()); var connStart = insB1.Count; var conns = insB2.Count; var outStart = connStart + conns; var count = outStart + outsB3.Count; var ins = new Inlet[count]; insB1.CopyTo(ins, 0); insB2.CopyTo(ins, insB1.Count); var inOwners = new int[count]; inOwnersB1.CopyTo(inOwners, 0); inOwnersB2.CopyTo(inOwners, inOwnersB1.Count); for (int i = inOwnersB1.Count + inOwnersB2.Count; i < inOwners.Length; i++) { inOwners[i] = -1; } var outs = new Outlet[count]; Array.Copy(outsB2, 0, outs, connStart, conns); outsB3.CopyTo(outs, outStart); var outOwners = new int[count]; for (int i = 0; i < connStart; i++) { outOwners[i] = -1; } Array.Copy(outOwnersB2, 0, outOwners, connStart, conns); outOwnersB3.CopyTo(outOwners, outStart); var firstModule = group.First(); if (!(firstModule is CopiedModule)) { throw new ArgumentException("unexpected module structure"); } var asyncAttrs = IsAsync((CopiedModule)firstModule) ? new Attributes(Attributes.AsyncBoundary.Instance) : Attributes.None; var dispatcher = GetDispatcher(firstModule); var dispatcherAttrs = dispatcher == null ? Attributes.None : new Attributes(dispatcher); var attr = asyncAttrs.And(dispatcherAttrs); return(new GraphModule(new GraphAssembly(stages, attributes, ins, inOwners, outs, outOwners), shape, attr, materializedValueIds)); }