private bool Matches(ItemTree declaredMembers, StringStore strings, int symbolIndex) { int candidateNameIdentifier = declaredMembers.GetNameIdentifier(symbolIndex); if (!SymbolNameSuffixIdentifiers.Contains(candidateNameIdentifier)) { return(false); } if (this.IgnoreCase == true) { return(true); } else { String8 candidateName8 = strings[candidateNameIdentifier]; if (this.IsFullSuffix) { return(this.SymbolNameSuffix.CompareTo(candidateName8, false) == 0); } else { return(this.SymbolNameSuffix.CompareAsPrefixTo(candidateName8, false) == 0); } } }
/// <summary> /// Search the given IMemberDatabase for matches to this query and put /// results into the results array provided. The capacity of the results /// array determines how many results are returned. /// </summary> /// <param name="db">Database to search</param> /// <param name="results">PartialArray to contain results, sized for the count desired.</param> /// <returns>True if results were added, False otherwise</returns> public bool TryFindMembers(IMemberDatabase db, ref PartialArray <Symbol> results) { // Ensure strings must be found again so that benchmarks are realistic ForceReresolve(); // Clear results from a previous query results.Clear(); // If there was no query, return with no results if (String.IsNullOrEmpty(SymbolName)) { return(false); } // Get required members from database StringStore strings = db.StringStore; ItemTree declaredMembers = db.DeclaredMembers; MemberIndex index = db.Index; // Map strings to the local StringStore. Stop immediately if any values aren't found. if (!ResolveStringsTo(strings)) { return(false); } // Cache whether this query needs details to match bool usesDetails = !this.Parameters8.IsEmpty() || this.Type != SymbolType.Any || this.Modifiers != SymbolModifier.None; int[] matches; int matchesIndex, matchesCount; if (SplitSymbolName8.Count == 1) { // Find the set of symbols with names in range. If no symbols in index, return nothing if (!index.TryGetMatchesInRange(SymbolNameSuffixIdentifiers, out matches, out matchesIndex, out matchesCount)) { return(false); } // If there was just one name part searched for, all matches count for (int i = matchesIndex; i < matchesIndex + matchesCount; ++i) { if ((usesDetails ? MatchesDetailed(declaredMembers, strings, db, matches[i]) : Matches(declaredMembers, strings, matches[i]))) { results.Add(new Symbol(db, matches[i])); if (results.IsFull) { return(true); } } } } else { // Find all entries with exactly the second-to-last name if (!index.TryGetMatchesInRange(SymbolNamePrefixIdentifiers[SymbolNamePrefixIdentifiers.Length - 1], out matches, out matchesIndex, out matchesCount)) { return(false); } for (int i = matchesIndex; i < matchesIndex + matchesCount; ++i) { int currentMatchIndex = matches[i]; // First, do all previous name parts in the query match? int currentAncestorIndex = currentMatchIndex; int namePartIndex = SymbolNamePrefixIdentifiers.Length - 2; for (; namePartIndex >= 0; --namePartIndex) { currentAncestorIndex = declaredMembers.GetParent(currentAncestorIndex); int currentAncestorNameIdentifier = declaredMembers.GetNameIdentifier(currentAncestorIndex); if (!SymbolNamePrefixIdentifiers[namePartIndex].Contains(currentAncestorNameIdentifier)) { break; } } if (namePartIndex != -1) { continue; } // If this was a full match, are we out of namespaces? if (IsFullNamespace) { currentAncestorIndex = declaredMembers.GetParent(currentAncestorIndex); SymbolType symbolAboveFullNameType = db.GetMemberType(currentAncestorIndex); if (!symbolAboveFullNameType.IsAboveNamespace()) { return(false); } } // Next, find children of this item which match the last part typed int leafId = declaredMembers.GetFirstChild(currentMatchIndex); while (leafId > 0) { if ((usesDetails ? MatchesDetailed(declaredMembers, strings, db, leafId) : Matches(declaredMembers, strings, leafId))) { results.Add(new Symbol(db, leafId)); if (results.IsFull) { return(true); } } leafId = declaredMembers.GetNextSibling(leafId); } } } return(results.Count > 0); }
public void ItemTree_Basic() { byte[] byteBuffer = new byte[100]; int[] intBuffer = new int[10]; String8Set splitPath8; StringStore strings = new StringStore(); ItemTree fileTree = new ItemTree(); string[] filePaths = { @"C:\Code\Arriba\Arriba\Diagnostics\DailyLogTraceListener.cs", @"C:\Code\Arriba\Arriba\Diagnostics\ProgressWriter.cs", @"C:\Code\Arriba\Arriba\Diagnostics\Log4NetDiagnosticConsumer.cs", @"C:\Code\Arriba\Arriba\Diagnostics\Memory.cs", @"C:\Code\Arriba\Arriba\Diagnostics\TraceWriter.cs" }; List <int> fileTreeIndexes = new List <int>(); // Index each file path foreach (string filePath in filePaths) { splitPath8 = String8.Convert(filePath, byteBuffer).Split('\\', intBuffer); fileTreeIndexes.Add(fileTree.AddPath(0, splitPath8, strings)); } for (int i = 0; i < filePaths.Length; ++i) { // Reconstruct each file path and confirm they match string rebuiltPath = fileTree.GetPath(fileTreeIndexes[i], strings, '\\').ToString(); Assert.AreEqual(filePaths[i], rebuiltPath); // Verify find by path works splitPath8 = String8.Convert(filePaths[i], byteBuffer).Split('\\', intBuffer); int foundAtIndex; Assert.IsTrue(fileTree.TryFindByPath(0, splitPath8, strings, out foundAtIndex)); Assert.AreEqual(fileTreeIndexes[i], foundAtIndex); } // Verify find works int foundIndex; // Root found under sentinel root Assert.IsTrue(fileTree.TryFindChildByName(0, strings.FindOrAddString("C:"), out foundIndex)); Assert.AreEqual(1, foundIndex); // Root not found under another node Assert.IsFalse(fileTree.TryFindChildByName(1, strings.FindOrAddString("C:"), out foundIndex)); // Node not found at root Assert.IsFalse(fileTree.TryFindChildByName(0, strings.FindOrAddString("Code"), out foundIndex)); // Node found under the right parent Assert.IsTrue(fileTree.TryFindChildByName(1, strings.FindOrAddString("Code"), out foundIndex)); Assert.AreEqual(2, foundIndex); // FindByPath works under a partial path splitPath8 = String8.Convert(@"Code\Arriba", byteBuffer).Split('\\', intBuffer); int arribaIndex; Assert.IsTrue(fileTree.TryFindByPath(1, splitPath8, strings, out arribaIndex)); splitPath8 = String8.Convert(@"Arriba\Diagnostics\DailyLogTraceListener.cs", byteBuffer).Split('\\', intBuffer); int dailyLogIndex; Assert.IsTrue(fileTree.TryFindByPath(arribaIndex, splitPath8, strings, out dailyLogIndex)); Assert.AreEqual(fileTreeIndexes[0], dailyLogIndex); // FindByPath returns the closest element when it fails splitPath8 = String8.Convert(@"C:\Nope", byteBuffer).Split('\\', intBuffer); int nopeIndex; Assert.IsFalse(fileTree.TryFindByPath(0, splitPath8, strings, out nopeIndex)); Assert.AreEqual(1, nopeIndex, @"Failed find for C:\Nope should return 'C:' index; the successful portion of the search."); splitPath8 = String8.Convert(@"C:\Code\Arriba\Arriba\Diagnostics\TraceWriter.cs\Nope", byteBuffer).Split('\\', intBuffer); Assert.IsFalse(fileTree.TryFindByPath(0, splitPath8, strings, out nopeIndex)); Assert.AreEqual(fileTreeIndexes[4], nopeIndex); // Verify depth works Assert.AreEqual(0, fileTree.GetDepth(0)); Assert.AreEqual(1, fileTree.GetDepth(1)); Assert.AreEqual(6, fileTree.GetDepth(fileTreeIndexes[0])); Assert.AreEqual("C:", strings[fileTree.GetNameIdentifier(fileTree.GetAncestorAtDepth(fileTreeIndexes[0], 1))].ToString()); Assert.AreEqual("Code", strings[fileTree.GetNameIdentifier(fileTree.GetAncestorAtDepth(fileTreeIndexes[0], 2))].ToString()); Assert.AreEqual("Arriba", strings[fileTree.GetNameIdentifier(fileTree.GetAncestorAtDepth(fileTreeIndexes[0], 3))].ToString()); Assert.AreEqual("Arriba", strings[fileTree.GetNameIdentifier(fileTree.GetAncestorAtDepth(fileTreeIndexes[0], 4))].ToString()); // Sort the tree by name fileTree.SortByName(strings); // Log the tree Trace.WriteLine(Write.ToString((w) => fileTree.WriteTree(w, strings, 1))); // Verify roundtrip ItemTree readTree = new ItemTree(); Verify.RoundTrip(fileTree, readTree); fileTree = readTree; // Reconstruct each file path for (int i = 0; i < filePaths.Length; ++i) { string rebuiltPath = fileTree.GetPath(fileTreeIndexes[i], strings, '\\').ToString(); Assert.AreEqual(filePaths[i], rebuiltPath); } }