From e28b009036c328c198a858eb696f3c8cbcbf0ece Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Wed, 19 Jan 2011 00:07:29 -0500 Subject: [PATCH] Speed up map processing considerably via a piece of a patch I've had sitting around for ages. --- common/content/events.js | 12 ++++++-- common/content/mappings.js | 63 ++++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/common/content/events.js b/common/content/events.js index f20a6315..b45c423c 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -393,6 +393,12 @@ var Events = Module("events", { return events.fromString(keys, unknownOk).map(events.closure.toString).join(""); }, + iterKeys: function (keys) { + let match, re = /<.*?>?>|[^<]/g; + while (match = re.exec(keys)) + yield match[0]; + }, + /** * Dispatches an event to an element as if it were a native event. * @@ -1177,7 +1183,7 @@ var Events = Module("events", { } let candidates = this.hive.getCandidates(this.main, command); - if (candidates.length == 0 && !map) { + if (candidates == 0 && !map) { [map] = this.pendingMap || []; this.pendingMap = null; if (map && map.arg) @@ -1200,7 +1206,7 @@ var Events = Module("events", { execute(map, null, this.count, key, command); return Events.KILL; } - else if (!event.skipmap && map && candidates.length == 0) { + else if (!event.skipmap && map && candidates == 0) { this.pendingMap = null; let count = this.pendingMotionMap ? "motionCount" : "count"; @@ -1230,7 +1236,7 @@ var Events = Module("events", { return execute(map, null, this.count, null, command) === Events.PASS ? Events.PASS : Events.KILL; } } - else if (!event.skipmap && this.hive.getCandidates(this.main, command).length > 0) { + else if (!event.skipmap && this.hive.getCandidates(this.main, command) > 0) { this.append(event); this.pendingMap = [map, command]; } diff --git a/common/content/mappings.js b/common/content/mappings.js index 7e88c23e..42bbcaf1 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -90,7 +90,7 @@ var Map = Class("Map", { */ hasName: function (name) this.keys.indexOf(name) >= 0, - keys: Class.memoize(function () this.names.map(mappings.expandLeader)), + get keys() this.names.map(mappings.expandLeader), /** * Execute the action for this mapping. @@ -149,7 +149,7 @@ var MapHive = Class("MapHive", { */ getStack: function getStack(mode) { if (!(mode in this.stacks)) - return this.stacks[mode] = []; + return this.stacks[mode] = MapHive.Stack(); return this.stacks[mode]; }, @@ -161,7 +161,9 @@ var MapHive = Class("MapHive", { * @returns {Map|null} */ add: function (mode, map) { - this.getStack(mode).push(map); + let stack = this.getStack(mode); + stack.push(map); + delete stack.states; }, /** @@ -171,21 +173,17 @@ var MapHive = Class("MapHive", { * @param {string} cmd The map name to match. * @returns {Map|null} */ - get: function (mode, cmd) array.nth(this.getStack(mode), function (m) m.hasName(cmd), 0), + get: function (mode, cmd) this.getStack(mode).mappings[cmd], /** - * Returns an array of maps with names starting with but not equal to + * Returns a count of maps with names starting with but not equal to * *prefix*. * * @param {Modes.Mode} mode The mode to search. * @param {string} prefix The map prefix string to match. - * @returns {Map[]} + * @returns {number) */ - getCandidates: function (mode, prefix) { - let filter = util.regexp("^" + util.regexp.escape(prefix) + ".").closure.test; - return this.getStack(mode) - .filter(function (map) map.keys.some(filter)); - }, + getCandidates: function (mode, prefix) this.getStack(mode).candidates[prefix] || 0, /** * Returns whether there is a user-defined mapping *cmd* for the specified @@ -195,7 +193,7 @@ var MapHive = Class("MapHive", { * @param {string} cmd The candidate key mapping. * @returns {boolean} */ - has: function (mode, cmd) this.getStack(mode).some(function (map) map.hasName(cmd)), + has: function (mode, cmd) this.getStack(mode).candidates[cmd] != null, /** * Remove the mapping named *cmd* for *mode*. @@ -204,13 +202,15 @@ var MapHive = Class("MapHive", { * @param {string} cmd The map name to match. */ remove: function (mode, cmd) { - for (let [i, map] in Iterator(this.getStack(mode))) { + let stack = this.getStack(mode); + for (let [i, map] in array.iterItems(stack)) { let j = map.names.indexOf(cmd); if (j >= 0) { + delete stack.states; map.names.splice(j, 1); if (map.names.length == 0) // FIX ME. for (let [mode, stack] in Iterator(this.stacks)) - this.stacks[mode] = stack.filter(function (m) m != map); + this.stacks[mode] = MapHive.Stack(stack.filter(function (m) m != map)); return; } } @@ -224,6 +224,38 @@ var MapHive = Class("MapHive", { clear: function (mode) { this.stacks[mode] = []; } +}, { + Stack: Class("Stack", Array, { + init: function (ary) { + let self = ary || []; + self.__proto__ = this.__proto__; + return self; + }, + + __iterator__: function () array.iterValues(this), + + get candidates() this.states.candidates, + get mappings() this.states.mappings, + + states: Class.memoize(function () { + var states = { + candidates: {}, + mappings: {} + }; + + for (let map in this) + for (let name in values(map.keys)) { + states.mappings[name] = map; + let state = ""; + for (let key in events.iterKeys(name)) { + state += key; + if (state !== name) + states.candidates[state] = (states.candidates[state] || 0) + 1 + } + } + return states; + }) + }) }); /** @@ -653,8 +685,7 @@ var Mappings = Module("mappings", { if (this.hasChanged) for (let hive in mappings.hives.iterValues()) for (let stack in values(hive.stacks)) - for (let map in values(stack)) - delete map.keys; + delete stack.states; return value; } });