Index: lib/matcher.js |
=================================================================== |
--- a/lib/matcher.js |
+++ b/lib/matcher.js |
@@ -146,16 +146,23 @@ |
/** |
* Blacklist/whitelist filter matching |
*/ |
class Matcher |
{ |
constructor() |
{ |
/** |
+ * Lookup table for keywords by their associated filter |
+ * @type {Map.<RegExpFilter,string>} |
+ * @private |
+ */ |
+ this._keywordByFilter = new Map(); |
+ |
+ /** |
* Lookup table for simple filters by their associated keyword |
* @type {Map.<string,(RegExpFilter|Set.<RegExpFilter>)>} |
* @private |
*/ |
this._simpleFiltersByKeyword = new Map(); |
/** |
* Lookup table for complex filters by their associated keyword |
@@ -173,35 +180,41 @@ |
this._filterMapsByType = new Map(); |
} |
/** |
* Removes all known filters |
*/ |
clear() |
{ |
+ this._keywordByFilter.clear(); |
this._simpleFiltersByKeyword.clear(); |
this._complexFiltersByKeyword.clear(); |
this._filterMapsByType.clear(); |
} |
/** |
* Adds a filter to the matcher |
* @param {RegExpFilter} filter |
*/ |
add(filter) |
{ |
+ if (this._keywordByFilter.has(filter)) |
+ return; |
+ |
// Look for a suitable keyword |
let keyword = this.findKeyword(filter); |
let locationOnly = filter.isLocationOnly(); |
addFilterByKeyword(filter, keyword, |
locationOnly ? this._simpleFiltersByKeyword : |
this._complexFiltersByKeyword); |
+ this._keywordByFilter.set(filter, keyword); |
+ |
if (locationOnly) |
return; |
for (let type of nonDefaultTypes(filter.contentType)) |
{ |
let map = this._filterMapsByType.get(type); |
if (!map) |
this._filterMapsByType.set(type, map = new Map()); |
@@ -211,23 +224,28 @@ |
} |
/** |
* Removes a filter from the matcher |
* @param {RegExpFilter} filter |
*/ |
remove(filter) |
{ |
- let keyword = this.findKeyword(filter); |
+ let keyword = this._keywordByFilter.get(filter); |
+ if (typeof keyword == "undefined") |
+ return; |
+ |
let locationOnly = filter.isLocationOnly(); |
removeFilterByKeyword(filter, keyword, |
locationOnly ? this._simpleFiltersByKeyword : |
this._complexFiltersByKeyword); |
+ this._keywordByFilter.delete(filter); |
+ |
if (locationOnly) |
return; |
for (let type of nonDefaultTypes(filter.contentType)) |
{ |
let map = this._filterMapsByType.get(type); |
if (map) |
removeFilterByKeyword(filter, keyword, map); |