Refactor & speed up styleSectionsEqual

This commit is contained in:
tophf 2017-03-24 04:19:56 +03:00
parent 19f1490f0a
commit d53db2d45c

View File

@ -367,13 +367,17 @@ function getDomains(url) {
function getType(o) { function getType(o) {
if (typeof o == "undefined" || typeof o == "string") { if (typeof o == 'undefined' || typeof o == 'string') {
return typeof o; return typeof o;
} }
if (o instanceof Array) { // with the persistent cachedStyles the Array reference is usually different
return "array"; // so let's check for e.g. type of 'every' which is only present on arrays
// (in the context of our extension)
if (o instanceof Array || typeof o.every == 'function') {
return 'array';
} }
throw "Not supported - " + o; console.warn('Unsupported type:', o);
return 'undefined';
} }
const namespacePattern = /^\s*(@namespace[^;]+;\s*)+$/; const namespacePattern = /^\s*(@namespace[^;]+;\s*)+$/;
@ -752,29 +756,56 @@ function styleSectionsEqual(styleA, styleB) {
if (styleA.sections.length != styleB.sections.length) { if (styleA.sections.length != styleB.sections.length) {
return false; return false;
} }
const properties = ['code', 'urlPrefixes', 'urls', 'domains', 'regexps']; const propNames = ['code', 'urlPrefixes', 'urls', 'domains', 'regexps'];
return styleA.sections.every(sectionA => const typeBcaches = [];
styleB.sections.some(sectionB => checkingEveryInA: for (let sectionA of styleA.sections) {
properties.every(property => sectionEquals(sectionA, sectionB, property)) const typeAcache = new Map();
) for (let name of propNames) {
); typeAcache.set(name, getType(sectionA[name]));
}
function sectionEquals(a, b, property) { lookingForDupeInB: for (let i = 0, sectionB; (sectionB = styleB.sections[i]); i++) {
const aProp = a[property], typeA = getType(aProp); const typeBcache = typeBcaches[i] = typeBcaches[i] || new Map();
const bProp = b[property], typeB = getType(bProp); comparingProps: for (let name of propNames) {
const propA = sectionA[name], typeA = typeAcache.get(name);
const propB = sectionB[name];
let typeB = typeBcache.get(name);
if (!typeB) {
typeB = getType(propB);
typeBcache.set(name, typeB);
}
if (typeA != typeB) { if (typeA != typeB) {
// consider empty arrays equivalent to lack of property const bothEmptyOrUndefined =
return ((typeA == 'undefined' || (typeA == 'array' && aProp.length == 0)) && (typeA == 'undefined' || (typeA == 'array' && propA.length == 0)) &&
(typeB == 'undefined' || (typeB == 'array' && bProp.length == 0))); (typeB == 'undefined' || (typeB == 'array' && propB.length == 0));
if (bothEmptyOrUndefined) {
continue comparingProps;
} else {
continue lookingForDupeInB;
}
} }
if (typeA == 'undefined') { if (typeA == 'undefined') {
return true; continue comparingProps;
} }
if (typeA == 'array') { if (typeA == 'array') {
return aProp.length == bProp.length && aProp.every(item => bProp.includes(item)); if (propA.length != propB.length) {
continue lookingForDupeInB;
} }
if (typeA == 'string') { for (let item of propA) {
return aProp == bProp; if (propB.indexOf(item) < 0) {
continue lookingForDupeInB;
} }
} }
continue comparingProps;
}
if (typeA == 'string' && propA != propB) {
continue lookingForDupeInB;
}
}
// dupe found
continue checkingEveryInA;
}
// dupe not found
return false;
}
return true;
} }