public void SimpleSlotDependencies() { List <DependentNode> nodes = new List <DependentNode>(); DependentNode a = new DependentNode(0, "a"), b = new DependentNode(1, "b"), c = new DependentNode(2, "c"); nodes.Add(a); nodes.Add(b); nodes.Add(c); TestHelpers.MatchSlots(b, a, 0, 0); TestHelpers.MatchSlots(b, c, 1, 0); NodeSlot resultSlot = ExecutionHelper.FindFirstNodeSlotInDependents(b, TestHelpers.ConvertToDictionary(nodes), 0); Assert.AreEqual(a.Id, resultSlot.NodeId); }
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; } } }