Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/matcher.js

Issue 29907586: Issue 6994 - Use shortcut matching for location only filters (Closed)
Patch Set: Address PS4, and rebase Created Oct. 24, 2018, 8:40 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 class Matcher 64 class Matcher
65 { 65 {
66 constructor() 66 constructor()
67 { 67 {
68 /** 68 /**
69 * Lookup table for filters by their associated keyword 69 * Lookup table for filters by their associated keyword
70 * @type {Map.<string,(Filter|Set.<Filter>)>} 70 * @type {Map.<string,(Filter|Set.<Filter>)>}
71 * @private 71 * @private
72 */ 72 */
73 this._filterByKeyword = new Map(); 73 this._filterByKeyword = new Map();
74
75 /**
76 * Lookup table for location only filters by their associated keyword
Manish Jethani 2018/10/24 21:35:28 Nit: I don't know if this is right, but I would ha
Jon Sonesen 2018/10/24 21:46:51 Acknowledged.
77 * for shortcut matching.
78 * @private
Manish Jethani 2018/10/24 21:35:28 Let's put @private last.
Jon Sonesen 2018/10/24 21:46:52 Acknowledged.
79 * @type {Map.<string,(Filter|Set.<Filter>)>}
80 */
81 this._fastFilterByKeyword = new Map();
Manish Jethani 2018/10/24 21:35:28 I'm thinking about the nomenclature here, about ho
Jon Sonesen 2018/10/24 21:46:52 I like this, it makes more sense from a reader's p
74 } 82 }
75 83
76 /** 84 /**
77 * Removes all known filters 85 * Removes all known filters
78 */ 86 */
79 clear() 87 clear()
80 { 88 {
81 this._filterByKeyword.clear(); 89 this._filterByKeyword.clear();
90 this._fastFilterByKeyword.clear();
82 } 91 }
83 92
84 /** 93 /**
85 * Adds a filter to the matcher 94 * Adds a filter to the matcher
86 * @param {RegExpFilter} filter 95 * @param {RegExpFilter} filter
87 */ 96 */
88 add(filter) 97 add(filter)
89 { 98 {
90 // Look for a suitable keyword 99 // Look for a suitable keyword
91 let keyword = this.findKeyword(filter); 100 let keyword = this.findKeyword(filter);
92 let set = this._filterByKeyword.get(keyword); 101 let filterMap = filter.isLocationOnly() ? this._fastFilterByKeyword :
102 this._filterByKeyword;
103 let set = filterMap.get(keyword);
104
93 if (typeof set == "undefined") 105 if (typeof set == "undefined")
94 { 106 {
95 this._filterByKeyword.set(keyword, filter); 107 filterMap.set(keyword, filter);
96 } 108 }
97 else if (set.size == 1) 109 else if (set.size == 1)
98 { 110 {
99 if (filter != set) 111 if (filter != set)
100 this._filterByKeyword.set(keyword, new Set([set, filter])); 112 filterMap.set(keyword, new Set([set, filter]));
101 } 113 }
102 else 114 else
103 { 115 {
104 set.add(filter); 116 set.add(filter);
105 } 117 }
106 } 118 }
107 119
108 /** 120 /**
109 * Removes a filter from the matcher 121 * Removes a filter from the matcher
110 * @param {RegExpFilter} filter 122 * @param {RegExpFilter} filter
111 */ 123 */
112 remove(filter) 124 remove(filter)
113 { 125 {
114 let keyword = this.findKeyword(filter); 126 let keyword = this.findKeyword(filter);
115 let set = this._filterByKeyword.get(keyword); 127 let filterMap = filter.isLocationOnly() ? this._fastFilterByKeyword :
128 this._filterByKeyword;
129 let set = filterMap.get(keyword);
130
116 if (typeof set == "undefined") 131 if (typeof set == "undefined")
117 return; 132 return;
118 133
119 if (set.size == 1) 134 if (set.size == 1)
120 { 135 {
121 if (filter == set) 136 if (filter == set)
122 this._filterByKeyword.delete(keyword); 137 filterMap.delete(keyword);
123 } 138 }
124 else 139 else
125 { 140 {
126 set.delete(filter); 141 set.delete(filter);
127 142
128 if (set.size == 1) 143 if (set.size == 1)
129 this._filterByKeyword.set(keyword, [...set][0]); 144 filterMap.set(keyword, [...set][0]);
130 } 145 }
131 } 146 }
132 147
133 /** 148 /**
134 * Chooses a keyword to be associated with the filter 149 * Chooses a keyword to be associated with the filter
135 * @param {Filter} filter 150 * @param {Filter} filter
136 * @returns {string} keyword or an empty string if no keyword could be found 151 * @returns {string} keyword or an empty string if no keyword could be found
137 * @protected 152 * @protected
138 */ 153 */
139 findKeyword(filter) 154 findKeyword(filter)
140 { 155 {
141 let result = ""; 156 let result = "";
142 let {pattern} = filter; 157 let {pattern} = filter;
143 if (pattern == null) 158 if (pattern == null)
144 return result; 159 return result;
145 160
146 let candidates = pattern.toLowerCase().match(allKeywordsRegExp); 161 let candidates = pattern.toLowerCase().match(allKeywordsRegExp);
147 if (!candidates) 162 if (!candidates)
148 return result; 163 return result;
149 164
150 let hash = this._filterByKeyword; 165 let hash = filter.isLocationOnly() ? this._fastFilterByKeyword :
166 this._filterByKeyword;
167
151 let resultCount = 0xFFFFFF; 168 let resultCount = 0xFFFFFF;
152 let resultLength = 0; 169 let resultLength = 0;
153 for (let i = 0, l = candidates.length; i < l; i++) 170 for (let i = 0, l = candidates.length; i < l; i++)
154 { 171 {
155 let candidate = candidates[i].substr(1); 172 let candidate = candidates[i].substr(1);
156 let filters = hash.get(candidate); 173 let filters = hash.get(candidate);
157 let count = typeof filters != "undefined" ? filters.size : 0; 174 let count = typeof filters != "undefined" ? filters.size : 0;
Manish Jethani 2018/10/25 00:49:42 We need `count` to be the sum of `this._simpleFilt
158 if (count < resultCount || 175 if (count < resultCount ||
159 (count == resultCount && candidate.length > resultLength)) 176 (count == resultCount && candidate.length > resultLength))
160 { 177 {
161 result = candidate; 178 result = candidate;
162 resultCount = count; 179 resultCount = count;
163 resultLength = candidate.length; 180 resultLength = candidate.length;
164 } 181 }
165 } 182 }
166 return result; 183 return result;
167 } 184 }
168 185
169 /** 186 /**
170 * Checks whether the entries for a particular keyword match a URL 187 * Checks whether the entries for a particular keyword match a URL
171 * @param {string} keyword 188 * @param {string} keyword
172 * @param {string} location 189 * @param {string} location
173 * @param {number} typeMask 190 * @param {number} typeMask
174 * @param {string} [docDomain] 191 * @param {string} [docDomain]
175 * @param {boolean} [thirdParty] 192 * @param {boolean} [thirdParty]
176 * @param {string} [sitekey] 193 * @param {string} [sitekey]
177 * @param {boolean} [specificOnly] 194 * @param {boolean} [specificOnly]
178 * @returns {?Filter} 195 * @returns {?Filter}
179 * @protected 196 * @protected
180 */ 197 */
181 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, 198 checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey,
182 specificOnly) 199 specificOnly)
183 { 200 {
184 let set = this._filterByKeyword.get(keyword); 201 let set = this._filterByKeyword.get(keyword);
185 if (typeof set == "undefined") 202 if (typeof set == "undefined")
Manish Jethani 2018/10/25 00:49:41 This is clearly wrong. We want to check all filter
203 {
204 let fastSet = this._fastFilterByKeyword.get(keyword);
205 if (typeof fastSet == "undefined")
206 return null;
207
208 for (let filter of fastSet)
209 {
210 if (specificOnly && filter.isGeneric() &&
211 !(filter instanceof WhitelistFilter))
212 continue;
213
214 if (filter.matchesLocation(location))
215 return filter;
216 }
186 return null; 217 return null;
218 }
187 219
188 for (let filter of set) 220 for (let filter of set)
189 { 221 {
190 if (specificOnly && filter.isGeneric() && 222 if (specificOnly && filter.isGeneric() &&
191 !(filter instanceof WhitelistFilter)) 223 !(filter instanceof WhitelistFilter))
192 continue; 224 continue;
193 225
194 if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey)) 226 if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey))
195 return filter; 227 return filter;
196 } 228 }
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 428
397 exports.CombinedMatcher = CombinedMatcher; 429 exports.CombinedMatcher = CombinedMatcher;
398 430
399 /** 431 /**
400 * Shared {@link CombinedMatcher} instance that should usually be used. 432 * Shared {@link CombinedMatcher} instance that should usually be used.
401 * @type {CombinedMatcher} 433 * @type {CombinedMatcher}
402 */ 434 */
403 let defaultMatcher = new CombinedMatcher(); 435 let defaultMatcher = new CombinedMatcher();
404 436
405 exports.defaultMatcher = defaultMatcher; 437 exports.defaultMatcher = defaultMatcher;
OLDNEW
« lib/filterClasses.js ('K') | « lib/filterClasses.js ('k') | test/filterListener.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld