mirror of https://github.com/gorhill/uBlock.git
performance work:
- refactor "domain=" option matcher in light of https://gorhill.github.io/obj-vs-set-vs-map/set-vs-regexp.html - reuse existing instance of "domain=" matchers and filters wherever possible
This commit is contained in:
parent
1a92fff641
commit
bacf5021e0
|
@ -259,126 +259,139 @@ var reURLPostHostnameAnchors = /[\/?#]/;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// Hostname test helpers: the optimal test function is picked
|
// Hostname test helpers: the optimal test function is picked according to the
|
||||||
// according to the content of the `domain` filter option,
|
// content of the `domain=` filter option.
|
||||||
|
|
||||||
var hostnameTestPicker = function(owner) {
|
// Re-factored in light of:
|
||||||
var domainOpt = owner.domainOpt;
|
// - https://gorhill.github.io/obj-vs-set-vs-map/set-vs-regexp.html
|
||||||
|
// The re-factoring made possible to reuse instances of a matcher. As of
|
||||||
|
// writing, I observed that just with EasyList, there were ~1,200 reused
|
||||||
|
// instances out of ~2,800.
|
||||||
|
|
||||||
|
var hnMatcherFactory = function(domainOpt) {
|
||||||
|
var me = hnMatcherFactory;
|
||||||
|
|
||||||
|
// Reuse last instance if possible.
|
||||||
|
if ( domainOpt === me.domainOpt ) {
|
||||||
|
return me.hnMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
me.domainOpt = domainOpt;
|
||||||
|
|
||||||
// Only one hostname
|
// Only one hostname
|
||||||
if ( domainOpt.indexOf('|') === -1 ) {
|
if ( domainOpt.indexOf('|') === -1 ) {
|
||||||
if ( domainOpt.startsWith('~') ) {
|
if ( domainOpt.charCodeAt(0) === 0x7E /* '~' */ ) {
|
||||||
owner._notHostname = domainOpt.slice(1);
|
return (me.hnMatcher = new me.Miss(domainOpt));
|
||||||
return hostnameMissTest;
|
|
||||||
}
|
}
|
||||||
return hostnameHitTest;
|
return (me.hnMatcher = new me.Hit(domainOpt));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiple hostnames: use a dictionary.
|
// Many hostnames.
|
||||||
var hostnames = domainOpt.split('|');
|
|
||||||
var i, hostname, dict;
|
|
||||||
|
|
||||||
// First find out whether we have a homogeneous dictionary
|
// Must be in set (none negated).
|
||||||
var hit = false, miss = false;
|
if ( domainOpt.indexOf('~') === -1 ) {
|
||||||
i = hostnames.length;
|
return (me.hnMatcher = new me.HitSet(domainOpt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must not be in set (all negated).
|
||||||
|
if ( me.reAllNegated.test(domainOpt) ) {
|
||||||
|
return (me.hnMatcher = new me.MissSet(domainOpt));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be in one set, but not in the other.
|
||||||
|
return (me.hnMatcher = new me.MixedSet(domainOpt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hnMatcherFactory.reAllNegated = /^~(?:[^|~]+\|~)+[^|~]+$/;
|
||||||
|
hnMatcherFactory.domainOpt = undefined;
|
||||||
|
hnMatcherFactory.hnMatcher = undefined;
|
||||||
|
|
||||||
|
hnMatcherFactory.Hit = function(domainOpt) {
|
||||||
|
this.hostname = domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.Hit.prototype.toDomainOpt = function() {
|
||||||
|
return this.hostname;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.Hit.prototype.test = function() {
|
||||||
|
var needle = this.hostname,
|
||||||
|
haystack = pageHostnameRegister;
|
||||||
|
return haystack.endsWith(needle) &&
|
||||||
|
(haystack.length === needle.length ||
|
||||||
|
haystack.charCodeAt(haystack.length - needle.length - 1) === 0x2E /* '.' */);
|
||||||
|
};
|
||||||
|
|
||||||
|
hnMatcherFactory.Miss = function(domainOpt) {
|
||||||
|
this.hostname = domainOpt.slice(1);
|
||||||
|
};
|
||||||
|
hnMatcherFactory.Miss.prototype.toDomainOpt = function() {
|
||||||
|
return '~' + this.hostname;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.Miss.prototype.test = function() {
|
||||||
|
var needle = this.hostname,
|
||||||
|
haystack = pageHostnameRegister;
|
||||||
|
return haystack.endsWith(needle) === false ||
|
||||||
|
(haystack.length !== needle.length &&
|
||||||
|
haystack.charCodeAt(haystack.length - needle.length - 1) !== 0x2E /* '.' */);
|
||||||
|
};
|
||||||
|
|
||||||
|
hnMatcherFactory.HitSet = function(domainOpt) {
|
||||||
|
this.domainOpt = domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.HitSet.prototype.oneOf = null;
|
||||||
|
hnMatcherFactory.HitSet.prototype.toDomainOpt = function() {
|
||||||
|
return this.domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.HitSet.prototype.init = function() {
|
||||||
|
this.oneOf = new RegExp('(?:^|\\.)(?:' + this.domainOpt.replace(/\./g, '\\.') + ')$');
|
||||||
|
};
|
||||||
|
hnMatcherFactory.HitSet.prototype.test = function() {
|
||||||
|
if ( this.oneOf === null ) { this.init(); }
|
||||||
|
return this.oneOf.test(pageHostnameRegister);
|
||||||
|
};
|
||||||
|
|
||||||
|
hnMatcherFactory.MissSet = function(domainOpt) {
|
||||||
|
this.domainOpt = domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.MissSet.prototype.noneOf = null;
|
||||||
|
hnMatcherFactory.MissSet.prototype.toDomainOpt = function() {
|
||||||
|
return this.domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.MissSet.prototype.init = function() {
|
||||||
|
this.noneOf = new RegExp('(?:^|\\.)(?:' + this.domainOpt.replace(/~/g, '').replace(/\./g, '\\.') + ')$');
|
||||||
|
};
|
||||||
|
hnMatcherFactory.MissSet.prototype.test = function() {
|
||||||
|
if ( this.noneOf === null ) { this.init(); }
|
||||||
|
return this.noneOf.test(pageHostnameRegister) === false;
|
||||||
|
};
|
||||||
|
|
||||||
|
hnMatcherFactory.MixedSet = function(domainOpt) {
|
||||||
|
this.domainOpt = domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.MixedSet.prototype.oneOf = null;
|
||||||
|
hnMatcherFactory.MixedSet.prototype.noneOf = null;
|
||||||
|
hnMatcherFactory.MixedSet.prototype.toDomainOpt = function() {
|
||||||
|
return this.domainOpt;
|
||||||
|
};
|
||||||
|
hnMatcherFactory.MixedSet.prototype.init = function() {
|
||||||
|
var oneOf = [], noneOf = [],
|
||||||
|
hostnames = this.domainOpt.split('|'),
|
||||||
|
i = hostnames.length,
|
||||||
|
hostname;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
if ( hostnames[i].startsWith('~') ) {
|
hostname = hostnames[i].replace(/\./g, '\\.');
|
||||||
miss = true;
|
if ( hostname.charCodeAt(0) === 0x7E /* '~' */ ) {
|
||||||
if ( hit ) {
|
noneOf.push(hostname.slice(1));
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
hit = true;
|
oneOf.push(hostname);
|
||||||
if ( miss ) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
this.oneOf = new RegExp('(?:^|\\.)(?:' + oneOf.join('|') + ')$');
|
||||||
|
this.noneOf = new RegExp('(?:^|\\.)(?:' + noneOf.join('|') + ')$');
|
||||||
// Heterogenous dictionary: this can happen, though VERY rarely.
|
|
||||||
// Spotted one occurrence in EasyList Lite (cjxlist.txt):
|
|
||||||
// domain=photobucket.com|~secure.photobucket.com
|
|
||||||
if ( hit && miss ) {
|
|
||||||
dict = owner._hostnameDict = new Map();
|
|
||||||
i = hostnames.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
hostname = hostnames[i];
|
|
||||||
if ( hostname.startsWith('~') ) {
|
|
||||||
dict.set(hostname.slice(1), false);
|
|
||||||
} else {
|
|
||||||
dict.set(hostname, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hostnameMixedSetTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Homogeneous dictionary.
|
|
||||||
dict = owner._hostnameDict = new Set();
|
|
||||||
i = hostnames.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
hostname = hostnames[i];
|
|
||||||
dict.add(hostname.startsWith('~') ? hostname.slice(1) : hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
return hit ? hostnameHitSetTest : hostnameMissSetTest;
|
|
||||||
};
|
};
|
||||||
|
hnMatcherFactory.MixedSet.prototype.test = function() {
|
||||||
var hostnameHitTest = function(owner) {
|
if ( this.oneOf === null ) { this.init(); }
|
||||||
var current = pageHostnameRegister;
|
var needle = pageHostnameRegister;
|
||||||
var target = owner.domainOpt;
|
return this.oneOf.test(needle) && this.noneOf.test(needle) === false;
|
||||||
return current.endsWith(target) &&
|
|
||||||
(current.length === target.length ||
|
|
||||||
current.charAt(current.length - target.length - 1) === '.');
|
|
||||||
};
|
|
||||||
|
|
||||||
var hostnameMissTest = function(owner) {
|
|
||||||
var current = pageHostnameRegister;
|
|
||||||
var target = owner._notHostname;
|
|
||||||
return current.endsWith(target) === false ||
|
|
||||||
(current.length !== target.length &&
|
|
||||||
current.charAt(current.length - target.length - 1) !== '.');
|
|
||||||
};
|
|
||||||
|
|
||||||
var hostnameHitSetTest = function(owner) {
|
|
||||||
var dict = owner._hostnameDict,
|
|
||||||
needle = pageHostnameRegister,
|
|
||||||
pos;
|
|
||||||
for (;;) {
|
|
||||||
if ( dict.has(needle) ) { return true; }
|
|
||||||
pos = needle.indexOf('.');
|
|
||||||
if ( pos === -1 ) { break; }
|
|
||||||
needle = needle.slice(pos + 1);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
var hostnameMissSetTest = function(owner) {
|
|
||||||
var dict = owner._hostnameDict,
|
|
||||||
needle = pageHostnameRegister,
|
|
||||||
pos;
|
|
||||||
for (;;) {
|
|
||||||
if ( dict.has(needle) ) { return false; }
|
|
||||||
pos = needle.indexOf('.');
|
|
||||||
if ( pos === -1 ) { break; }
|
|
||||||
needle = needle.slice(pos + 1);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
var hostnameMixedSetTest = function(owner) {
|
|
||||||
var dict = owner._hostnameDict,
|
|
||||||
needle = pageHostnameRegister,
|
|
||||||
hit = false,
|
|
||||||
v, pos;
|
|
||||||
for (;;) {
|
|
||||||
v = dict.get(needle);
|
|
||||||
if ( v === false ) { return false; }
|
|
||||||
if ( v === true ) { hit = true; }
|
|
||||||
pos = needle.indexOf('.');
|
|
||||||
if ( pos === -1 ) { break; }
|
|
||||||
needle = needle.slice(pos + 1);
|
|
||||||
}
|
|
||||||
return hit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -443,13 +456,11 @@ FilterPlain.fromSelfie = function(s) {
|
||||||
var FilterPlainHostname = function(s, tokenBeg, domainOpt) {
|
var FilterPlainHostname = function(s, tokenBeg, domainOpt) {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.tokenBeg = tokenBeg;
|
this.tokenBeg = tokenBeg;
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainHostname.prototype.match = function(url, tokenBeg) {
|
FilterPlainHostname.prototype.match = function(url, tokenBeg) {
|
||||||
return url.startsWith(this.s, tokenBeg - this.tokenBeg) &&
|
return url.startsWith(this.s, tokenBeg - this.tokenBeg) && this.hnMatcher.test();
|
||||||
this.hostnameTest(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainHostname.fid =
|
FilterPlainHostname.fid =
|
||||||
|
@ -458,7 +469,7 @@ FilterPlainHostname.prototype.rtfid = 'ah';
|
||||||
|
|
||||||
FilterPlainHostname.prototype.toSelfie =
|
FilterPlainHostname.prototype.toSelfie =
|
||||||
FilterPlainHostname.prototype.rtCompile = function() {
|
FilterPlainHostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.tokenBeg + '\t' + this.domainOpt;
|
return this.s + '\t' + this.tokenBeg + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainHostname.compile = function(details) {
|
FilterPlainHostname.compile = function(details) {
|
||||||
|
@ -501,13 +512,11 @@ FilterPlainPrefix0.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterPlainPrefix0Hostname = function(s, domainOpt) {
|
var FilterPlainPrefix0Hostname = function(s, domainOpt) {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainPrefix0Hostname.prototype.match = function(url, tokenBeg) {
|
FilterPlainPrefix0Hostname.prototype.match = function(url, tokenBeg) {
|
||||||
return url.startsWith(this.s, tokenBeg) &&
|
return url.startsWith(this.s, tokenBeg) && this.hnMatcher.test();
|
||||||
this.hostnameTest(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainPrefix0Hostname.fid =
|
FilterPlainPrefix0Hostname.fid =
|
||||||
|
@ -516,7 +525,7 @@ FilterPlainPrefix0Hostname.prototype.rtfid = '0ah';
|
||||||
|
|
||||||
FilterPlainPrefix0Hostname.prototype.toSelfie =
|
FilterPlainPrefix0Hostname.prototype.toSelfie =
|
||||||
FilterPlainPrefix0Hostname.prototype.rtCompile = function() {
|
FilterPlainPrefix0Hostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.domainOpt;
|
return this.s + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainPrefix0Hostname.compile = function(details) {
|
FilterPlainPrefix0Hostname.compile = function(details) {
|
||||||
|
@ -559,13 +568,11 @@ FilterPlainPrefix1.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterPlainPrefix1Hostname = function(s, domainOpt) {
|
var FilterPlainPrefix1Hostname = function(s, domainOpt) {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainPrefix1Hostname.prototype.match = function(url, tokenBeg) {
|
FilterPlainPrefix1Hostname.prototype.match = function(url, tokenBeg) {
|
||||||
return url.startsWith(this.s, tokenBeg - 1) &&
|
return url.startsWith(this.s, tokenBeg - 1) && this.hnMatcher.test();
|
||||||
this.hostnameTest(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainPrefix1Hostname.fid =
|
FilterPlainPrefix1Hostname.fid =
|
||||||
|
@ -574,7 +581,7 @@ FilterPlainPrefix1Hostname.prototype.rtfid = '1ah';
|
||||||
|
|
||||||
FilterPlainPrefix1Hostname.prototype.toSelfie =
|
FilterPlainPrefix1Hostname.prototype.toSelfie =
|
||||||
FilterPlainPrefix1Hostname.prototype.rtCompile = function() {
|
FilterPlainPrefix1Hostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.domainOpt;
|
return this.s + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainPrefix1Hostname.compile = function(details) {
|
FilterPlainPrefix1Hostname.compile = function(details) {
|
||||||
|
@ -617,13 +624,11 @@ FilterPlainLeftAnchored.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterPlainLeftAnchoredHostname = function(s, domainOpt) {
|
var FilterPlainLeftAnchoredHostname = function(s, domainOpt) {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainLeftAnchoredHostname.prototype.match = function(url) {
|
FilterPlainLeftAnchoredHostname.prototype.match = function(url) {
|
||||||
return url.startsWith(this.s) &&
|
return url.startsWith(this.s) && this.hnMatcher.test();
|
||||||
this.hostnameTest(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainLeftAnchoredHostname.fid =
|
FilterPlainLeftAnchoredHostname.fid =
|
||||||
|
@ -632,7 +637,7 @@ FilterPlainLeftAnchoredHostname.prototype.rtfid = '|ah';
|
||||||
|
|
||||||
FilterPlainLeftAnchoredHostname.prototype.toSelfie =
|
FilterPlainLeftAnchoredHostname.prototype.toSelfie =
|
||||||
FilterPlainLeftAnchoredHostname.prototype.rtCompile = function() {
|
FilterPlainLeftAnchoredHostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.domainOpt;
|
return this.s + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainLeftAnchoredHostname.compile = function(details) {
|
FilterPlainLeftAnchoredHostname.compile = function(details) {
|
||||||
|
@ -675,13 +680,11 @@ FilterPlainRightAnchored.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterPlainRightAnchoredHostname = function(s, domainOpt) {
|
var FilterPlainRightAnchoredHostname = function(s, domainOpt) {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainRightAnchoredHostname.prototype.match = function(url) {
|
FilterPlainRightAnchoredHostname.prototype.match = function(url) {
|
||||||
return url.endsWith(this.s) &&
|
return url.endsWith(this.s) && this.hnMatcher.test();
|
||||||
this.hostnameTest(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainRightAnchoredHostname.fid =
|
FilterPlainRightAnchoredHostname.fid =
|
||||||
|
@ -690,7 +693,7 @@ FilterPlainRightAnchoredHostname.prototype.rtfid = 'a|h';
|
||||||
|
|
||||||
FilterPlainRightAnchoredHostname.prototype.toSelfie =
|
FilterPlainRightAnchoredHostname.prototype.toSelfie =
|
||||||
FilterPlainRightAnchoredHostname.prototype.rtCompile = function() {
|
FilterPlainRightAnchoredHostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.domainOpt;
|
return this.s + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainRightAnchoredHostname.compile = function(details) {
|
FilterPlainRightAnchoredHostname.compile = function(details) {
|
||||||
|
@ -742,13 +745,12 @@ FilterPlainHnAnchored.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterPlainHnAnchoredHostname = function(s, domainOpt) {
|
var FilterPlainHnAnchoredHostname = function(s, domainOpt) {
|
||||||
this.s = s;
|
this.s = s;
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainHnAnchoredHostname.prototype.match = function(url, tokenBeg) {
|
FilterPlainHnAnchoredHostname.prototype.match = function(url, tokenBeg) {
|
||||||
return url.startsWith(this.s, tokenBeg) &&
|
return url.startsWith(this.s, tokenBeg) &&
|
||||||
this.hostnameTest(this) &&
|
this.hnMatcher.test() &&
|
||||||
isHnAnchored(url, tokenBeg);
|
isHnAnchored(url, tokenBeg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -758,7 +760,7 @@ FilterPlainHnAnchoredHostname.prototype.rtfid = '||ah';
|
||||||
|
|
||||||
FilterPlainHnAnchoredHostname.prototype.toSelfie =
|
FilterPlainHnAnchoredHostname.prototype.toSelfie =
|
||||||
FilterPlainHnAnchoredHostname.prototype.rtCompile = function() {
|
FilterPlainHnAnchoredHostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.domainOpt;
|
return this.s + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterPlainHnAnchoredHostname.compile = function(details) {
|
FilterPlainHnAnchoredHostname.compile = function(details) {
|
||||||
|
@ -811,15 +813,13 @@ FilterGeneric.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterGenericHostname = function(s, anchor, domainOpt) {
|
var FilterGenericHostname = function(s, anchor, domainOpt) {
|
||||||
FilterGeneric.call(this, s, anchor);
|
FilterGeneric.call(this, s, anchor);
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
FilterGenericHostname.prototype = Object.create(FilterGeneric.prototype);
|
FilterGenericHostname.prototype = Object.create(FilterGeneric.prototype);
|
||||||
FilterGenericHostname.prototype.constructor = FilterGenericHostname;
|
FilterGenericHostname.prototype.constructor = FilterGenericHostname;
|
||||||
|
|
||||||
FilterGenericHostname.prototype.match = function(url) {
|
FilterGenericHostname.prototype.match = function(url) {
|
||||||
return this.hostnameTest(this) &&
|
return this.hnMatcher.test() && FilterGeneric.prototype.match.call(this, url);
|
||||||
FilterGeneric.prototype.match.call(this, url);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterGenericHostname.fid =
|
FilterGenericHostname.fid =
|
||||||
|
@ -828,7 +828,7 @@ FilterGenericHostname.prototype.rtfid = '_h';
|
||||||
|
|
||||||
FilterGenericHostname.prototype.toSelfie =
|
FilterGenericHostname.prototype.toSelfie =
|
||||||
FilterGenericHostname.prototype.rtCompile = function() {
|
FilterGenericHostname.prototype.rtCompile = function() {
|
||||||
return FilterGeneric.prototype.toSelfie.call(this) + '\t' + this.domainOpt;
|
return FilterGeneric.prototype.toSelfie.call(this) + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterGenericHostname.compile = function(details) {
|
FilterGenericHostname.compile = function(details) {
|
||||||
|
@ -882,15 +882,13 @@ FilterGenericHnAnchored.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterGenericHnAnchoredHostname = function(s, anchor, domainOpt) {
|
var FilterGenericHnAnchoredHostname = function(s, anchor, domainOpt) {
|
||||||
FilterGenericHnAnchored.call(this, s, anchor);
|
FilterGenericHnAnchored.call(this, s, anchor);
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
FilterGenericHnAnchoredHostname.prototype = Object.create(FilterGenericHnAnchored.prototype);
|
FilterGenericHnAnchoredHostname.prototype = Object.create(FilterGenericHnAnchored.prototype);
|
||||||
FilterGenericHnAnchoredHostname.prototype.constructor = FilterGenericHnAnchoredHostname;
|
FilterGenericHnAnchoredHostname.prototype.constructor = FilterGenericHnAnchoredHostname;
|
||||||
|
|
||||||
FilterGenericHnAnchoredHostname.prototype.match = function(url) {
|
FilterGenericHnAnchoredHostname.prototype.match = function(url) {
|
||||||
return this.hostnameTest(this) &&
|
return this.hnMatcher.test() && FilterGenericHnAnchored.prototype.match.call(this, url);
|
||||||
FilterGenericHnAnchored.prototype.match.call(this, url);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterGenericHnAnchoredHostname.fid =
|
FilterGenericHnAnchoredHostname.fid =
|
||||||
|
@ -899,7 +897,7 @@ FilterGenericHnAnchoredHostname.prototype.rtfid = '||_h';
|
||||||
|
|
||||||
FilterGenericHnAnchoredHostname.prototype.toSelfie =
|
FilterGenericHnAnchoredHostname.prototype.toSelfie =
|
||||||
FilterGenericHnAnchoredHostname.prototype.rtCompile = function() {
|
FilterGenericHnAnchoredHostname.prototype.rtCompile = function() {
|
||||||
return this.s + '\t' + this.anchor + '\t' + this.domainOpt;
|
return this.s + '\t' + this.anchor + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterGenericHnAnchoredHostname.compile = function(details) {
|
FilterGenericHnAnchoredHostname.compile = function(details) {
|
||||||
|
@ -944,14 +942,12 @@ FilterRegex.fromSelfie = function(s) {
|
||||||
|
|
||||||
var FilterRegexHostname = function(s, domainOpt) {
|
var FilterRegexHostname = function(s, domainOpt) {
|
||||||
this.re = new RegExp(s, 'i');
|
this.re = new RegExp(s, 'i');
|
||||||
this.domainOpt = domainOpt;
|
this.hnMatcher = hnMatcherFactory(domainOpt);
|
||||||
this.hostnameTest = hostnameTestPicker(this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterRegexHostname.prototype.match = function(url) {
|
FilterRegexHostname.prototype.match = function(url) {
|
||||||
// test hostname first, it's cheaper than evaluating a regex
|
// test hostname first, it's cheaper than evaluating a regex
|
||||||
return this.hostnameTest(this) &&
|
return this.hnMatcher.test() && this.re.test(url);
|
||||||
this.re.test(url);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterRegexHostname.fid =
|
FilterRegexHostname.fid =
|
||||||
|
@ -960,7 +956,7 @@ FilterRegexHostname.prototype.rtfid = '//h';
|
||||||
|
|
||||||
FilterRegexHostname.prototype.toSelfie =
|
FilterRegexHostname.prototype.toSelfie =
|
||||||
FilterRegexHostname.prototype.rtCompile = function() {
|
FilterRegexHostname.prototype.rtCompile = function() {
|
||||||
return this.re.source + '\t' + this.domainOpt;
|
return this.re.source + '\t' + this.hnMatcher.toDomainOpt();
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterRegexHostname.compile = function(details) {
|
FilterRegexHostname.compile = function(details) {
|
||||||
|
@ -1582,6 +1578,11 @@ FilterContainer.prototype.reset = function() {
|
||||||
this.filterParser.reset();
|
this.filterParser.reset();
|
||||||
this.filterCounts = {};
|
this.filterCounts = {};
|
||||||
|
|
||||||
|
// Reuse filter instances whenever possible at load time.
|
||||||
|
this.fclassLast = null;
|
||||||
|
this.fdataLast = null;
|
||||||
|
this.filterLast = null;
|
||||||
|
|
||||||
// Runtime registers
|
// Runtime registers
|
||||||
this.keyRegister = undefined;
|
this.keyRegister = undefined;
|
||||||
this.tokenRegister = undefined;
|
this.tokenRegister = undefined;
|
||||||
|
@ -1594,6 +1595,9 @@ FilterContainer.prototype.freeze = function() {
|
||||||
histogram('allFilters', this.categories);
|
histogram('allFilters', this.categories);
|
||||||
this.duplicateBuster = new Set();
|
this.duplicateBuster = new Set();
|
||||||
this.filterParser.reset();
|
this.filterParser.reset();
|
||||||
|
this.fclassLast = null;
|
||||||
|
this.fdataLast = null;
|
||||||
|
this.filterLast = null;
|
||||||
this.frozen = true;
|
this.frozen = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1624,6 +1628,17 @@ FilterContainer.prototype.factories = {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
FilterContainer.prototype.filterFromSelfie = function(fclass, fdata) {
|
||||||
|
if ( fdata !== this.fdataLast || fclass !== this.fclassLast ) {
|
||||||
|
this.fclassLast = fclass;
|
||||||
|
this.fdataLast = fdata;
|
||||||
|
this.filterLast = this.factories[fclass].fromSelfie(fdata);
|
||||||
|
}
|
||||||
|
return this.filterLast;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterContainer.prototype.toSelfie = function() {
|
FilterContainer.prototype.toSelfie = function() {
|
||||||
var categoryToSelfie = function(map) {
|
var categoryToSelfie = function(map) {
|
||||||
var selfie = [],
|
var selfie = [],
|
||||||
|
@ -1631,15 +1646,11 @@ FilterContainer.prototype.toSelfie = function() {
|
||||||
entry, bucket, ff, f;
|
entry, bucket, ff, f;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
entry = iterator.next();
|
entry = iterator.next();
|
||||||
if ( entry.done ) {
|
if ( entry.done ) { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
selfie.push('k2\t' + entry.value[0]);
|
selfie.push('k2\t' + entry.value[0]);
|
||||||
bucket = entry.value[1];
|
bucket = entry.value[1];
|
||||||
selfie.push(bucket.fid + '\t' + bucket.toSelfie());
|
selfie.push(bucket.fid + '\t' + bucket.toSelfie());
|
||||||
if ( bucket.fid !== '[]' ) {
|
if ( bucket.fid !== '[]' ) { continue; }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ff = bucket.filters;
|
ff = bucket.filters;
|
||||||
for ( var i = 0, ni = ff.length; i < ni; i++ ) {
|
for ( var i = 0, ni = ff.length; i < ni; i++ ) {
|
||||||
f = ff[i];
|
f = ff[i];
|
||||||
|
@ -1655,9 +1666,7 @@ FilterContainer.prototype.toSelfie = function() {
|
||||||
entry;
|
entry;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
entry = iterator.next();
|
entry = iterator.next();
|
||||||
if ( entry.done ) {
|
if ( entry.done ) { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
selfie.push('k1\t' + entry.value[0]);
|
selfie.push('k1\t' + entry.value[0]);
|
||||||
selfie.push(categoryToSelfie(entry.value[1]));
|
selfie.push(categoryToSelfie(entry.value[1]));
|
||||||
}
|
}
|
||||||
|
@ -1692,7 +1701,7 @@ FilterContainer.prototype.fromSelfie = function(selfie) {
|
||||||
var rawText = selfie.categories;
|
var rawText = selfie.categories;
|
||||||
var rawEnd = rawText.length;
|
var rawEnd = rawText.length;
|
||||||
var lineBeg = 0, lineEnd;
|
var lineBeg = 0, lineEnd;
|
||||||
var line, pos, what, factory;
|
var line, pos, what, data, filter;
|
||||||
while ( lineBeg < rawEnd ) {
|
while ( lineBeg < rawEnd ) {
|
||||||
lineEnd = rawText.indexOf('\n', lineBeg);
|
lineEnd = rawText.indexOf('\n', lineBeg);
|
||||||
if ( lineEnd < 0 ) {
|
if ( lineEnd < 0 ) {
|
||||||
|
@ -1702,27 +1711,28 @@ FilterContainer.prototype.fromSelfie = function(selfie) {
|
||||||
lineBeg = lineEnd + 1;
|
lineBeg = lineEnd + 1;
|
||||||
pos = line.indexOf('\t');
|
pos = line.indexOf('\t');
|
||||||
what = line.slice(0, pos);
|
what = line.slice(0, pos);
|
||||||
|
data = line.slice(pos + 1);
|
||||||
if ( what === 'k1' ) {
|
if ( what === 'k1' ) {
|
||||||
catKey = line.slice(pos + 1);
|
catKey = data;
|
||||||
submap = new Map();
|
submap = new Map();
|
||||||
map.set(catKey, submap);
|
map.set(catKey, submap);
|
||||||
bucket = null;
|
bucket = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( what === 'k2' ) {
|
if ( what === 'k2' ) {
|
||||||
tokenKey = line.slice(pos + 1);
|
tokenKey = data;
|
||||||
bucket = null;
|
bucket = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
factory = this.factories[what];
|
filter = this.filterFromSelfie(what, data);
|
||||||
if ( bucket === null ) {
|
if ( bucket === null ) {
|
||||||
bucket = factory.fromSelfie(line.slice(pos + 1));
|
bucket = filter;
|
||||||
submap.set(tokenKey, bucket);
|
submap.set(tokenKey, bucket);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// When token key is reused, it can't be anything
|
// When token key is reused, it can't be anything
|
||||||
// else than FilterBucket
|
// else than FilterBucket
|
||||||
bucket.add(factory.fromSelfie(line.slice(pos + 1)));
|
bucket.add(filter);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1946,7 +1956,7 @@ FilterContainer.prototype.compileToAtomicFilter = function(filterClass, parsed,
|
||||||
|
|
||||||
FilterContainer.prototype.fromCompiledContent = function(lineIter) {
|
FilterContainer.prototype.fromCompiledContent = function(lineIter) {
|
||||||
var line, hash, token, fclass, fdata,
|
var line, hash, token, fclass, fdata,
|
||||||
bucket, entry, factory, filter,
|
bucket, entry, filter,
|
||||||
fieldIter = new µb.FieldIterator('\v');
|
fieldIter = new µb.FieldIterator('\v');
|
||||||
|
|
||||||
while ( lineIter.eot() === false ) {
|
while ( lineIter.eot() === false ) {
|
||||||
|
@ -1996,9 +2006,7 @@ FilterContainer.prototype.fromCompiledContent = function(lineIter) {
|
||||||
}
|
}
|
||||||
this.duplicateBuster.add(line);
|
this.duplicateBuster.add(line);
|
||||||
|
|
||||||
factory = this.factories[fclass];
|
filter = this.filterFromSelfie(fclass, fdata);
|
||||||
|
|
||||||
filter = factory.fromSelfie(fdata);
|
|
||||||
if ( entry === undefined ) {
|
if ( entry === undefined ) {
|
||||||
bucket.set(token, filter);
|
bucket.set(token, filter);
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in New Issue