From 785eb31c8d39b6ffbe1896455e487488486d8423 Mon Sep 17 00:00:00 2001 From: LeopoldTal Date: Sat, 31 Oct 2020 12:12:05 +0100 Subject: [PATCH] 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. --- src/js/savegame/savegame_compressor.js | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/js/savegame/savegame_compressor.js b/src/js/savegame/savegame_compressor.js index bc14baf7..ac82ebda 100644 --- a/src/js/savegame/savegame_compressor.js +++ b/src/js/savegame/savegame_compressor.js @@ -59,7 +59,7 @@ if (G_IS_DEV) { } } -function compressObjectInternal(obj, keys = [], values = []) { +function compressObjectInternal(obj, keys, values) { if (Array.isArray(obj)) { let result = []; for (let i = 0; i < obj.length; ++i) { @@ -69,33 +69,41 @@ function compressObjectInternal(obj, keys = [], values = []) { } else if (typeof obj === "object" && obj !== null) { let result = {}; for (const key in obj) { - let index = keys.indexOf(key); - if (index < 0) { - keys.push(key); - index = keys.length - 1; + let index = keys.get(key); + if (index === undefined) { + index = keys.size; + keys.set(key, index); } const value = obj[key]; result[compressInt(index)] = compressObjectInternal(value, keys, values); } return result; } else if (typeof obj === "string") { - let index = values.indexOf(obj); - if (index < 0) { - values.push(obj); - index = values.length - 1; + let index = values.get(obj); + if (index === undefined) { + index = values.size; + values.set(obj, index); } return compressInt(index); } return obj; } +function indexMapToArray(hashMap) { + const result = []; + hashMap.forEach((index, key) => { + result[index] = key; + }); + return result; +} + export function compressObject(obj) { - const keys = []; - const values = []; + const keys = new Map(); + const values = new Map(); const data = compressObjectInternal(obj, keys, values); return { - keys, - values, + keys: indexMapToArray(keys), + values: indexMapToArray(values), data, }; }