private void FindLoopPairs(DependentNode loopEnd, ref List <int> foundEnds, int depth = 0) { LoopPair instance = new LoopPair(); instance.Id = loopIdCount++; if (loopEnd.Type == LoopEnd.TypeName) { instance.End = new LoopEnd(loopEnd, instance); instance.Depth = depth; int startNode = ExecutionHelper.FindFirstNodeSlotInDependencies(loopEnd, dependencyGraph, 0).NodeId; if (startNode == -1) { throw new MissingLinkException("No link for loop start specified"); } DependentNode loopStart = dependencyGraph[startNode]; //try to keep one instance per unique loop start node Id if (loopStarts.ContainsKey(startNode)) { instance.Start = loopStarts[startNode]; } else { instance.Start = new LoopStart(loopStart); loopStarts.Add(startNode, instance.Start); } //ensure that only the start and end nodes are linked if (loopStart.Dependents.Where((testSlot, b) => { bool incorrectType = dependencyGraph[testSlot.NodeId].Type != LoopEnd.TypeName; foreach (NodeSlot slot in dependencyGraph[testSlot.NodeId].Dependencies) { if (slot.NodeId == loopStart.Id && slot.SlotPos == 0) { if (incorrectType) { return(true); } } } return(false); }).Any()) { throw new InvalidNodeException("Loop Start Link (slot 0) cannot link to anything but a Loop End"); } //find out how many loops the "LoopStart" node is directly responsible for int loopCount; { List <int> matched = new List <int>(); loopCount = loopStart.Dependents.Where((testSlot, b) => { if (matched.Contains(testSlot.NodeId)) { return(false); } foreach (NodeSlot slot in dependencyGraph[testSlot.NodeId].Dependencies) { if (slot.NodeId == loopStart.Id && slot.SlotPos == 0) { matched.Add(testSlot.NodeId); return(true); } } return(false); }).Count(); } if (loopCount > 1) { throw new SlotLimitExceeded("Loop Start may only have one loop end, use multiple loop starts for nesting or branching"); #region //multiple nodes linked so there must be nested loops sharing this start position /*int[] ids = new int[loopCount]; * for (int i = 0, c = 0; i < loopStart.Dependents.Length; i++) * if (loopStart.Dependents[i].SlotPos == 0) * ids[c++] = loopStart.Dependents[i].NodeId; * * //check if co dependent nodes exist * List<int> dependencies = new List<int>(); * for (int a = 0; a < ids.Length; a++) * { * for (int b = 0; b < ids.Length; b++) * { * if (a == b) continue; * * bool aTob = NodeDependentOn(ids[a], ids[b]), * bToa = NodeDependentOn(ids[b], ids[a]); * * if (aTob && bToa) throw new CoDependentLoopException * ("Node " + ids[a] + " and " + ids[b] + "Are dependent on each other and can't loop!"); * * if (aTob && !dependencies.Contains(a)) dependencies.Add(ids[a]); * } * } * * //check non dependent nodes for internal loops * foreach (int id in ids) * { * if (dependencies.Contains(id)) continue; * * LoopPair subPair = new LoopPair(); * subPair.Id = loopIdCount++; * subPair.Depth = depth; * subPair.End = new LoopEnd(dependencyGraph[id], subPair); * if (loopStarts.ContainsKey(loopEnd.Dependencies[0].NodeId)) * subPair.Start = loopStarts[loopEnd.Dependencies[0].NodeId]; * else * { * instance.Start = new LoopStart(dependencyGraph[loopEnd.Dependencies[0].NodeId]); * loopStarts.Add(loopEnd.Dependencies[0].NodeId, subPair.Start); * } * * int foundEnd; * if (ContainsLoop(instance, out foundEnd)) * //contains internal loop * FindLoopPairs(dependencyGraph[foundEnd], ref foundEnds, subPair.Depth + 1); * * foundEnds.Add(subPair.End.NodeId); * subPair.Start.AddLoopPair(ref subPair); * loopPairs.Add(subPair); * } * * //go back and handle the nodes which are dependent on each other * if (dependencies.Count > 1) * { * throw new NotImplementedException(); * //todo * }*/ #endregion } else { NodeSlot startLink = ExecutionHelper.FindFirstNodeSlotInDependents(loopStart, dependencyGraph, 0); if (startLink.NodeId == -1) { throw new MissingLinkException("No link for loop start specified"); } if (startLink.NodeId != loopEnd.Id) { throw new MissingLinkException(StartEndIdMismatch); } int foundEnd; //contains internal loop? if (ContainsLoop(instance, out foundEnd)) { FindLoopPairs(dependencyGraph[foundEnd], ref foundEnds, instance.Depth + 1); } instance.ContainedNodes = FindContainingNodeIds(instance.Start.NodeId, instance.End.NodeId); int start = 0, end = 0; foreach (NodeSlot nodes in instance.ContainedNodes) { if (dependencyGraph[nodes.NodeId].Type == LoopStart.TypeName) { start += 1; } else if (dependencyGraph[nodes.NodeId].Type == LoopEnd.TypeName) { end += 1; } } if (start != end) { throw new CoDependentLoopException(); } foundEnds.Add(instance.End.NodeId); instance.Start.AddLoopPair(ref instance); loopPairs.Add(instance); } } else if (loopEnd.Type == LoopStart.TypeName) { //abort as you are in the middle of a loop rather than at the end if (instance.End == null) { return; } } }
/// <summary> /// Checks if the loop has ended /// </summary> /// <param name="data"></param> /// <param name="dependencyGraph"></param> /// <returns>next set of Ids to be triggered</returns> public int[] Finished(DataStore data, Dictionary <int, DependentNode> dependencyGraph) { //check condition bool done = false; { //find the "done" result NodeSlot search = ExecutionHelper.FindFirstNodeSlotInDependencies(node, dependencyGraph, 1); if (search.NodeId == -1) { return(new int[0]); } byte[] result = data.getData(search); if (result == null) { return(new int[0]); } if (Convert.ToBoolean(result[0])) { done = true; } } //trigger dependencies and iterate loop start depth if (done) { //move the data through to the output of the node List <byte[]> transferData = new List <byte[]>(); for (int j = 2; j < node.Dependencies.Length; j++) { for (var i = 0; i < node.Dependencies.Length; i++) { NodeSlot slot = node.Dependencies[i]; int slotPos = ExecutionHelper.OtherNodeSlotDependents(dependencyGraph[slot.NodeId], node.Id); //slot 0 and 1 are loop node slots, all other data must be passed on if (slotPos == j) { transferData.Add(data.getData(node.Dependencies[i])); break; } } } data.StoreResults(transferData, NodeId); //trigger next nodes List <int> ids = new List <int>(); foreach (NodeSlot slot in node.Dependents) { if (!ids.Contains(slot.NodeId)) { ids.Add(slot.NodeId); } } return(ids.ToArray()); } //move loop end input data to the loop start output //so that it can be used in the next cycle List <byte[]> outputData = new List <byte[]>(); outputData.Add(new byte[0]); //loop start Link slot outputData.Add(BitConverter.GetBytes(++pair.Iteration)); //loop start increment slot for (int j = 2; j < node.Dependencies.Length; j++) { for (var i = 0; i < node.Dependencies.Length; i++) { NodeSlot slot = node.Dependencies[i]; int slotPos = ExecutionHelper.OtherNodeSlotDependents(dependencyGraph[slot.NodeId], node.Id); //slot 0 and 1 are loop node slots, all other data must be passed on if (slotPos == j) { outputData.Add(data.getData(node.Dependencies[i])); break; } } } data.ClearResults(pair.ContainedNodes); data.StoreResults(outputData, pair.Start.NodeId); return(pair.Start.StartDependencies(NodeId, data)); }