public static TSource ContainsSingle <TSource>(IEnumerable <TSource> enumerable, Func <TSource, bool> expectedPredicate) { if (expectedPredicate is null) { throw new ArgumentNullException(nameof(expectedPredicate)); } var lp = new LoopProtection(); var hasFoundItem = false; TSource matchingItem = default; foreach (var item in enumerable) { lp.Iterate(); if (expectedPredicate(item)) { if (hasFoundItem) { throw new AssertionException($"{enumerable} contains more than one element"); } else { hasFoundItem = true; matchingItem = item; } } } if (hasFoundItem) { return(matchingItem !); } throw new AssertionException($"{enumerable} contains no items satisfying the supplied condition"); }
public static void DoesNotContain <TSource>(IEnumerable <TSource> enumerable, TSource expectedItem) { var lp = new LoopProtection(); foreach (var item in enumerable) { lp.Iterate(); if (Equals(item, expectedItem)) { throw new AssertionException($"{enumerable} does contain {expectedItem}"); } } }
public static void None <TSource>(IEnumerable <TSource> enumerable, Func <TSource, bool> excludedPredicate) { if (excludedPredicate is null) { throw new ArgumentNullException(nameof(excludedPredicate)); } var lp = new LoopProtection(); foreach (var item in enumerable) { lp.Iterate(); if (excludedPredicate(item)) { throw new AssertionException($"{item} matching excluded condition found in {enumerable}"); } } }
protected override bool Apply(Subgraph subgraph, NodeGraph fullGraph) { if (fullGraph.Nodes.GetOrDefaultFromReadOnly(_rootNodeKey) is not { } rootNode) { return(false); } var modified = false; var nodesSeen = new HashSet <Node>(); var nodesToExplore = new Queue <Node>(); void TryEnqueue(Node toEnqueue) { if (nodesSeen.Add(toEnqueue)) { nodesToExplore.Enqueue(toEnqueue); } } TryEnqueue(rootNode); var lp = new LoopProtection(); while (nodesToExplore.Count > 0) { lp.Iterate(); var current = nodesToExplore.Dequeue(); var links = _isDependent ? current.BackLinks : current.ForwardLinks; foreach (var dependency in links) { if (dependency.LinkType.HasFlagPartially(_dependencyRelationship)) { TryEnqueue(_isDependent ? dependency.Dependent : dependency.Dependency); } } } foreach (var found in nodesSeen) { modified |= subgraph.AddPinnedNode(found.Key, fullGraph); } return(modified); }
public static TSource Contains <TSource>(IEnumerable <TSource> enumerable, Func <TSource, bool> expectedPredicate) { if (expectedPredicate is null) { throw new ArgumentNullException(nameof(expectedPredicate)); } var lp = new LoopProtection(); foreach (var item in enumerable) { lp.Iterate(); if (expectedPredicate(item)) { return(item); } } throw new AssertionException($"{enumerable} contains no items satisfying the supplied condition"); }
public static IEnumerable <NodePath> GetMultiDependencyRootPaths(NodeGraph graph, ISet <Node> roots) { if (roots.Count < 2) { throw new ArgumentOutOfRangeException(nameof(roots)); } var toExplore = new Queue <SearchEntry>(); var nodesSeen = new HashSet <Node>(); foreach (var root in roots) { toExplore.Clear(); nodesSeen.Clear(); var rootsNotFound = roots.Count - 1; toExplore.Enqueue(new SearchEntry(root, previous: null, generation: 0)); var lp = new LoopProtection(); while (toExplore.Count > 0) { lp.Iterate(); var current = toExplore.Dequeue(); foreach (var link in current.Node.ForwardLinkNodes) { if (nodesSeen.Contains(link)) { // Seen before, is either in queue or already explored (or is a root) continue; } // Mark as seen nodesSeen.Add(link); if (roots.Contains(link) && link != root) { // We've found another root yield return(NodePath.FromSearch(current, link)); rootsNotFound--; // Note: we don't add it to the explore queue, because we don't want paths with more than 2 roots. Any connections out of that root // will be found when that root is processed. } else { // Regular node we haven't seen - queue it up to explore toExplore.Enqueue(current.NextGeneration(link)); } if (rootsNotFound == 0) { // All roots have been found for this root, go to the next one break; } } if (rootsNotFound == 0) { // All roots have been found for this root, go to the next one break; } } } }
private async Task <ICollection <Node> > UpdateNode(Node node, CompilationCache compilationCache, CancellationToken ct) { var(symbol, project) = await compilationCache.GetSymbolForNode(node, ct); if (symbol == null) { // It's gone! Clear node (remove all its forward links and back links). Back links need to be invalidated. var dirtied = new HashSet <Node>(); var lp = new LoopProtection(); while (node.ForwardLinks.Count > 0) { lp.Iterate(); var forwardLink = node.ForwardLinks.First(); dirtied.Add(forwardLink.Dependency); node.RemoveForwardLink(forwardLink); } while (node.BackLinks.Count > 0) { lp.Iterate(); var backLink = node.BackLinks.First(); var backLinkNode = backLink.Dependent; dirtied.Add(backLinkNode); backLinkNode.RemoveForwardLink(node); InvalidateNode(backLinkNode); } return(dirtied); } // Reconcile AssociatedFiles (including _nodesByDocument) var associated = GetAssociatedFiles(symbol); var fileDiffs = associated.GetUnorderedDiff(node.AssociatedFiles); if (fileDiffs.IsDifferent) { foreach (var added in fileDiffs.Added) { AddAssociatedFile(node, added); } foreach (var removed in fileDiffs.Removed) { RemoveAssociatedFile(node, removed); } } var dependencySymbols = await symbol.GetTypeDependencies(compilationCache, project, includeExternalMetadata : false, ct) .Where(IsSymbolIncluded) .ToListAsync(); var symbolsForDependencies = dependencySymbols.ToDictionary(s => (Node)GetOrCreateNode(s, compilationCache)); var dependencies = symbolsForDependencies.Keys; if (ct.IsCancellationRequested) { return(ArrayUtils.GetEmpty <Node>()); } var diffs = dependencies.GetUnorderedDiff(node.ForwardLinkNodes); if (diffs.IsDifferent) { var dirtied = new HashSet <Node>(); dirtied.Add(node); foreach (var removedItem in diffs.Removed) { node.RemoveForwardLink(removedItem); dirtied.Add(removedItem); } foreach (var addedItem in diffs.Added) { if (addedItem != node) { var linkType = GetLinkType(symbolsForDependencies[addedItem], symbol); node.AddForwardLink(addedItem, linkType); } dirtied.Add(addedItem); } return(dirtied); } return(ArrayUtils.GetEmpty <Node>()); }