simplify/modularize styleSectionsEqual
+ 1.5x speedup thanks to checkedInB memoization + more strict type comparison + two-way array comparison (more correct, even if there's no practical difference)
This commit is contained in:
parent
db1dc0df7b
commit
dcfb8ad356
108
storage.js
108
storage.js
|
@ -333,69 +333,52 @@ function styleCodeEmpty(code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function styleSectionsEqual(styleA, styleB) {
|
function styleSectionsEqual({sections: a}, {sections: b}) {
|
||||||
if (!styleA.sections || !styleB.sections) {
|
if (!a || !b) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (styleA.sections.length != styleB.sections.length) {
|
if (a.length != b.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const propNames = ['code', 'urlPrefixes', 'urls', 'domains', 'regexps'];
|
const checkedInB = [];
|
||||||
const typeBcaches = [];
|
return a.every(sectionA => b.some(sectionB => {
|
||||||
checkingEveryInA:
|
if (!checkedInB.includes(sectionB) && propertiesEqual(sectionA, sectionB)) {
|
||||||
for (const sectionA of styleA.sections) {
|
checkedInB.push(sectionB);
|
||||||
const typeAcache = new Map();
|
return true;
|
||||||
for (const name of propNames) {
|
|
||||||
typeAcache.set(name, getType(sectionA[name]));
|
|
||||||
}
|
}
|
||||||
lookingForDupeInB:
|
}));
|
||||||
for (let i = 0, sectionB; (sectionB = styleB.sections[i]); i++) {
|
|
||||||
const typeBcache = typeBcaches[i] = typeBcaches[i] || new Map();
|
function propertiesEqual(secA, secB) {
|
||||||
comparingProps:
|
for (const name of ['urlPrefixes', 'urls', 'domains', 'regexps']) {
|
||||||
for (const name of propNames) {
|
if (!equalOrEmpty(secA[name], secB[name], 'every', arrayMirrors)) {
|
||||||
const propA = sectionA[name];
|
return false;
|
||||||
const 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) {
|
|
||||||
const bothEmptyOrUndefined =
|
|
||||||
(typeA == 'undefined' || (typeA == 'array' && propA.length == 0)) &&
|
|
||||||
(typeB == 'undefined' || (typeB == 'array' && propB.length == 0));
|
|
||||||
if (bothEmptyOrUndefined) {
|
|
||||||
continue comparingProps;
|
|
||||||
} else {
|
|
||||||
continue lookingForDupeInB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeA == 'undefined') {
|
|
||||||
continue comparingProps;
|
|
||||||
}
|
|
||||||
if (typeA == 'array') {
|
|
||||||
if (propA.length != propB.length) {
|
|
||||||
continue lookingForDupeInB;
|
|
||||||
}
|
|
||||||
for (const item of propA) {
|
|
||||||
if (propB.indexOf(item) < 0) {
|
|
||||||
continue lookingForDupeInB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue comparingProps;
|
|
||||||
}
|
|
||||||
if (typeA == 'string' && propA != propB) {
|
|
||||||
continue lookingForDupeInB;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// dupe found
|
|
||||||
continue checkingEveryInA;
|
|
||||||
}
|
}
|
||||||
// dupe not found
|
return equalOrEmpty(secA.code, secB.code, 'substr', (a, b) => a == b);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
function equalOrEmpty(a, b, telltale, comparator) {
|
||||||
|
const typeA = a && typeof a[telltale] == 'function';
|
||||||
|
const typeB = b && typeof b[telltale] == 'function';
|
||||||
|
return (
|
||||||
|
(a === null || a === undefined || (typeA && !a.length)) &&
|
||||||
|
(b === null || b === undefined || (typeB && !b.length))
|
||||||
|
) || typeA && typeB && a.length == b.length && comparator(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayMirrors(array1, array2) {
|
||||||
|
for (const el of array1) {
|
||||||
|
if (array2.indexOf(el) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const el of array2) {
|
||||||
|
if (array1.indexOf(el) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -515,18 +498,3 @@ function getDomains(url) {
|
||||||
}
|
}
|
||||||
return domains;
|
return domains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getType(o) {
|
|
||||||
if (typeof o == 'undefined' || typeof o == 'string') {
|
|
||||||
return typeof o;
|
|
||||||
}
|
|
||||||
// with the persistent cachedStyles the Array reference is usually different
|
|
||||||
// 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';
|
|
||||||
}
|
|
||||||
console.warn('Unsupported type:', o);
|
|
||||||
return 'undefined';
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user