Index: lib/matcher.js |
=================================================================== |
--- a/lib/matcher.js |
+++ b/lib/matcher.js |
@@ -66,72 +66,87 @@ |
constructor() |
{ |
/** |
* Lookup table for filters by their associated keyword |
* @type {Map.<string,(Filter|Set.<Filter>)>} |
* @private |
*/ |
this._filterByKeyword = new Map(); |
+ |
+ /** |
+ * 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.
|
+ * for shortcut matching. |
+ * @private |
Manish Jethani
2018/10/24 21:35:28
Let's put @private last.
Jon Sonesen
2018/10/24 21:46:52
Acknowledged.
|
+ * @type {Map.<string,(Filter|Set.<Filter>)>} |
+ */ |
+ 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
|
} |
/** |
* Removes all known filters |
*/ |
clear() |
{ |
this._filterByKeyword.clear(); |
+ this._fastFilterByKeyword.clear(); |
} |
/** |
* Adds a filter to the matcher |
* @param {RegExpFilter} filter |
*/ |
add(filter) |
{ |
// Look for a suitable keyword |
let keyword = this.findKeyword(filter); |
- let set = this._filterByKeyword.get(keyword); |
+ let filterMap = filter.isLocationOnly() ? this._fastFilterByKeyword : |
+ this._filterByKeyword; |
+ let set = filterMap.get(keyword); |
+ |
if (typeof set == "undefined") |
{ |
- this._filterByKeyword.set(keyword, filter); |
+ filterMap.set(keyword, filter); |
} |
else if (set.size == 1) |
{ |
if (filter != set) |
- this._filterByKeyword.set(keyword, new Set([set, filter])); |
+ filterMap.set(keyword, new Set([set, filter])); |
} |
else |
{ |
set.add(filter); |
} |
} |
/** |
* Removes a filter from the matcher |
* @param {RegExpFilter} filter |
*/ |
remove(filter) |
{ |
let keyword = this.findKeyword(filter); |
- let set = this._filterByKeyword.get(keyword); |
+ let filterMap = filter.isLocationOnly() ? this._fastFilterByKeyword : |
+ this._filterByKeyword; |
+ let set = filterMap.get(keyword); |
+ |
if (typeof set == "undefined") |
return; |
if (set.size == 1) |
{ |
if (filter == set) |
- this._filterByKeyword.delete(keyword); |
+ filterMap.delete(keyword); |
} |
else |
{ |
set.delete(filter); |
if (set.size == 1) |
- this._filterByKeyword.set(keyword, [...set][0]); |
+ filterMap.set(keyword, [...set][0]); |
} |
} |
/** |
* Chooses a keyword to be associated with the filter |
* @param {Filter} filter |
* @returns {string} keyword or an empty string if no keyword could be found |
* @protected |
@@ -142,17 +157,19 @@ |
let {pattern} = filter; |
if (pattern == null) |
return result; |
let candidates = pattern.toLowerCase().match(allKeywordsRegExp); |
if (!candidates) |
return result; |
- let hash = this._filterByKeyword; |
+ let hash = filter.isLocationOnly() ? this._fastFilterByKeyword : |
+ this._filterByKeyword; |
+ |
let resultCount = 0xFFFFFF; |
let resultLength = 0; |
for (let i = 0, l = candidates.length; i < l; i++) |
{ |
let candidate = candidates[i].substr(1); |
let filters = hash.get(candidate); |
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
|
if (count < resultCount || |
@@ -178,17 +195,32 @@ |
* @returns {?Filter} |
* @protected |
*/ |
checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, |
specificOnly) |
{ |
let set = this._filterByKeyword.get(keyword); |
if (typeof set == "undefined") |
Manish Jethani
2018/10/25 00:49:41
This is clearly wrong. We want to check all filter
|
+ { |
+ let fastSet = this._fastFilterByKeyword.get(keyword); |
+ if (typeof fastSet == "undefined") |
+ return null; |
+ |
+ for (let filter of fastSet) |
+ { |
+ if (specificOnly && filter.isGeneric() && |
+ !(filter instanceof WhitelistFilter)) |
+ continue; |
+ |
+ if (filter.matchesLocation(location)) |
+ return filter; |
+ } |
return null; |
+ } |
for (let filter of set) |
{ |
if (specificOnly && filter.isGeneric() && |
!(filter instanceof WhitelistFilter)) |
continue; |
if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey)) |