make save compressor faster (#888)

Fixes #836 by using a Map instead of an array. The Map maps the values to their indices rather than the reverse, making finding the index constant-time rather than linear, and so building the full map linear rather than quadratic. Flipping it to build the final array is also linear.
This commit is contained in:
LeopoldTal 2020-10-31 12:12:05 +01:00 committed by GitHub
parent 61f3b1991f
commit 785eb31c8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 21 additions and 13 deletions

View File

@ -59,7 +59,7 @@ if (G_IS_DEV) {
} }
} }
function compressObjectInternal(obj, keys = [], values = []) { function compressObjectInternal(obj, keys, values) {
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
let result = []; let result = [];
for (let i = 0; i < obj.length; ++i) { for (let i = 0; i < obj.length; ++i) {
@ -69,33 +69,41 @@ function compressObjectInternal(obj, keys = [], values = []) {
} else if (typeof obj === "object" && obj !== null) { } else if (typeof obj === "object" && obj !== null) {
let result = {}; let result = {};
for (const key in obj) { for (const key in obj) {
let index = keys.indexOf(key); let index = keys.get(key);
if (index < 0) { if (index === undefined) {
keys.push(key); index = keys.size;
index = keys.length - 1; keys.set(key, index);
} }
const value = obj[key]; const value = obj[key];
result[compressInt(index)] = compressObjectInternal(value, keys, values); result[compressInt(index)] = compressObjectInternal(value, keys, values);
} }
return result; return result;
} else if (typeof obj === "string") { } else if (typeof obj === "string") {
let index = values.indexOf(obj); let index = values.get(obj);
if (index < 0) { if (index === undefined) {
values.push(obj); index = values.size;
index = values.length - 1; values.set(obj, index);
} }
return compressInt(index); return compressInt(index);
} }
return obj; return obj;
} }
function indexMapToArray(hashMap) {
const result = [];
hashMap.forEach((index, key) => {
result[index] = key;
});
return result;
}
export function compressObject(obj) { export function compressObject(obj) {
const keys = []; const keys = new Map();
const values = []; const values = new Map();
const data = compressObjectInternal(obj, keys, values); const data = compressObjectInternal(obj, keys, values);
return { return {
keys, keys: indexMapToArray(keys),
values, values: indexMapToArray(values),
data, data,
}; };
} }