public IEnumerable <Match <T> > EnumerateMatches <T>(IGlobMatchableHierarchy <T> hierarchy) { var start = new GlobMatchFactory(hierarchy.CaseSensitive).Start(glob); var worklist = new Worklist <Match <T> >(); worklist.Add(new Match <T>(hierarchy.Root, start)); while (worklist.TryTake(out var pair)) { foreach (var child in hierarchy.GetChildrenMatchingPrefix(pair.Item, pair.Details.GetPrefixFilter())) { var newState = pair.Details.MatchChild(hierarchy.GetName(child)); if (newState.IsMatch) { yield return(new Match <T>(child, newState)); } if (newState.CanContinue && hierarchy.IsContainer(child)) { worklist.Add(new Match <T>(child, newState)); } } } }
public IEnumerable <MultiMatch <T> > EnumerateMatches <T>(IGlobMatchableHierarchy <T> hierarchy) { var factory = new GlobMatchFactory(hierarchy.CaseSensitive); var starts = rules.Select(r => new Rule(factory.Start(r.Glob), r.Exclude)).ToArray(); var worklist = new Worklist <State <T> >(); worklist.Add(new State <T>(hierarchy.Root, starts)); var newStates = new List <Rule>(); var matches = new List <GlobMatch>(); while (worklist.TryTake(out var pair)) { var includePrefix = GetCommonPrefix(pair.Current.Where(c => !c.Exclude)); if (includePrefix == null) { continue; // No inclusions remaining for this node. } foreach (var child in hierarchy.GetChildrenMatchingPrefix(pair.Item, includePrefix)) { var name = hierarchy.GetName(child); var isContainer = hierarchy.IsContainer(child); var isExcluded = false; newStates.Clear(); matches.Clear(); foreach (var state in pair.Current) { var newState = state.Details.MatchChild(name); if (state.Exclude) { if (newState.IsMatch) { isExcluded = true; } if (newState.MatchesAllChildren) { // Early exit: entire subtree is ignored for subsequent rules. break; } } else if (!isExcluded) { if (newState.IsMatch) { matches.Add(newState); } } if (newState.CanContinue && isContainer) { newStates.Add(new Rule(newState, state.Exclude)); } } if (matches.Any()) { yield return(new MultiMatch <T>(child, matches.ToArray())); } if (newStates.Any()) { worklist.Add(new State <T>(child, newStates.ToArray())); } } } string?GetCommonPrefix(IEnumerable <Rule> states) { var prefixes = states.Select(s => s.Details.GetPrefixFilter()).ToList(); if (prefixes.Count == 0) { return(null); } return(Util.LongestCommonPrefix(prefixes, hierarchy.CaseSensitive)); } }