@@ -89,17 +89,69 @@ void SpecialCaseList::GlobMatcher::preprocess(bool BySize) {
8989 return A.Name .size () < B.Name .size ();
9090 });
9191 }
92+
93+ for (const auto &G : Globs) {
94+ StringRef Prefix = G.Pattern .prefix ();
95+ StringRef Suffix = G.Pattern .suffix ();
96+
97+ if (Suffix.empty () && Prefix.empty ()) {
98+ // If both prefix and suffix are empty put into special tree to search by
99+ // substring in a middle.
100+ StringRef Substr = G.Pattern .longest_substr ();
101+ if (!Substr.empty ()) {
102+ // But only if substring is not empty. Searching this tree is more
103+ // expensive.
104+ auto &V = SubstrToGlob.emplace (Substr).first ->second ;
105+ V.emplace_back (&G);
106+ continue ;
107+ }
108+ }
109+
110+ auto &PToGlob = SuffixPrefixToGlob.emplace (reverse (Suffix)).first ->second ;
111+ auto &V = PToGlob.emplace (Prefix).first ->second ;
112+ V.emplace_back (&G);
113+ }
92114}
93115
94116void SpecialCaseList::GlobMatcher::match (
95117 StringRef Query,
96118 llvm::function_ref<void (StringRef Rule, unsigned LineNo)> Cb) const {
97- for (const auto &G : reverse (Globs))
98- if (G.Pattern .match (Query))
99- return Cb (G.Name , G.LineNo );
119+ if (!SuffixPrefixToGlob.empty ()) {
120+ for (const auto &[_, PToGlob] :
121+ SuffixPrefixToGlob.find_prefixes (reverse (Query))) {
122+ for (const auto &[_, V] : PToGlob.find_prefixes (Query)) {
123+ for (const auto *G : V) {
124+ // Each value of the map is a vector of globs ordered from the best to
125+ // the worst.
126+ if (G->Pattern .match (Query)) {
127+ Cb (G->Name , G->LineNo );
128+ // As soon as we find a match in the vector we can break for the
129+ // vector, still we can't return, and need to continue for others
130+ // values in the map, as they may contain a better match.
131+ break ;
132+ }
133+ }
134+ }
135+ }
136+ }
137+
138+ if (!SubstrToGlob.empty ()) {
139+ // As we don't know when substring exactly starts, we will try all
140+ // possibilities. In most cases search will fail on first characters.
141+ for (StringRef Q = Query; !Q.empty (); Q = Q.drop_front ()) {
142+ for (const auto &[_, V] : SubstrToGlob.find_prefixes (Q)) {
143+ for (const auto *G : reverse (V)) {
144+ if (G->Pattern .match (Query)) {
145+ Cb (G->Name , G->LineNo );
146+ break ;
147+ }
148+ }
149+ }
150+ }
151+ }
100152}
101153
102- SpecialCaseList::Matcher::Matcher (bool UseGlobs, bool RemoveDotSlash)
154+ SpecialCaseList::Matcher::Matcher (bool UseGlobs, bool RemoveDotSlash)
103155 : RemoveDotSlash(RemoveDotSlash) {
104156 if (UseGlobs)
105157 M.emplace <GlobMatcher>();
0 commit comments