提交 941812fd 编写于 作者: A Alex Dima

Memory usage improvements in KeybindingResolver

上级 0d3ac4fd
......@@ -404,40 +404,48 @@ export namespace KeyCodeUtils {
}
}
// Binary encoding strategy:
// 15: 1 bit for ctrlCmd
// 14: 1 bit for shift
// 13: 1 bit for alt
// 12: 1 bit for winCtrl
// 0: 12 bits for keyCode (up to a maximum keyCode of 4096. Given we have 83 at this point thats good enough)
/**
* Binary encoding strategy:
* ```
* 1111 11
* 5432 1098 7654 3210
* ---- CSAW KKKK KKKK
* C = bit 11 = ctrlCmd flag
* S = bit 10 = shift flag
* A = bit 9 = alt flag
* W = bit 8 = winCtrl flag
* K = bits 0-7 = key code
* ```
*/
const enum BinaryKeybindingsMask {
CtrlCmd = 1 << 15,
Shift = 1 << 14,
Alt = 1 << 13,
WinCtrl = 1 << 12,
KeyCode = 0x00000fff,
CtrlCmd = (1 << 11) >>> 0,
Shift = (1 << 10) >>> 0,
Alt = (1 << 9) >>> 0,
WinCtrl = (1 << 8) >>> 0,
KeyCode = 0x000000ff,
ModifierMask = CtrlCmd | Shift | Alt | WinCtrl
}
export const enum KeyMod {
CtrlCmd = 1 << 15,
Shift = 1 << 14,
Alt = 1 << 13,
WinCtrl = 1 << 12,
CtrlCmd = (1 << 11) >>> 0,
Shift = (1 << 10) >>> 0,
Alt = (1 << 9) >>> 0,
WinCtrl = (1 << 8) >>> 0,
}
export function KeyChord(firstPart: number, secondPart: number): number {
return firstPart | ((secondPart & 0x0000ffff) << 16);
let chordPart = ((secondPart & 0x0000ffff) << 16) >>> 0;
return (firstPart | chordPart) >>> 0;
}
export class BinaryKeybindings {
public static extractFirstPart(keybinding: number): number {
return keybinding & 0x0000ffff;
return (keybinding & 0x0000ffff) >>> 0;
}
public static extractChordPart(keybinding: number): number {
return (keybinding >> 16) & 0x0000ffff;
return (keybinding & 0xffff0000) >>> 16;
}
public static hasChord(keybinding: number): boolean {
......
......@@ -66,13 +66,11 @@ export class KeybindingResolver {
private _defaultBoundCommands: IBoundCommands;
private _map: ICommandMap;
private _chords: IChordsMap;
private _lookupMap: {
[commandId: string]: NormalizedKeybindingItem[];
};
private _lookupMapUnreachable: {
// The value contains the keybinding or first part of a chord
[commandId: string]: number[];
};
private _lookupMap: Map<string, ArrayBuffer>;
/**
* The value contains the keybinding or first part of a chord
*/
private _lookupMapUnreachable: Map<string, ArrayBuffer>;
private _shouldWarnOnConflict: boolean;
constructor(defaultKeybindings: IKeybindingItem[], overrides: IKeybindingItem[], shouldWarnOnConflict: boolean = true) {
......@@ -87,8 +85,8 @@ export class KeybindingResolver {
}
this._map = Object.create(null);
this._lookupMap = Object.create(null);
this._lookupMapUnreachable = Object.create(null);
this._lookupMap = new Map<string, ArrayBuffer>();
this._lookupMapUnreachable = new Map<string, ArrayBuffer>();
this._chords = Object.create(null);
let allKeybindings = KeybindingResolver.combine(defaultKeybindings, overrides);
......@@ -194,8 +192,7 @@ export class KeybindingResolver {
if (this._shouldWarnOnConflict && item.isDefault) {
console.warn('Conflict detected, command `' + conflict.commandId + '` cannot be triggered by ' + KeybindingLabels.toUserSettingsLabel(keypress) + ' due to ' + item.command);
}
this._lookupMapUnreachable[conflict.commandId] = this._lookupMapUnreachable[conflict.commandId] || [];
this._lookupMapUnreachable[conflict.commandId].push(conflict.keybinding);
KeybindingResolver._push(this._lookupMapUnreachable, conflict.commandId, conflict.keybinding);
}
}
......@@ -237,12 +234,40 @@ export class KeybindingResolver {
return true;
}
private static _push(map: Map<string, ArrayBuffer>, key: string, value: number): void {
let oldRawEntries = map.get(key);
if (typeof oldRawEntries === 'undefined') {
let entries = new Uint32Array(1);
entries[0] = value;
map.set(key, entries.buffer);
} else {
let oldEntries = new Uint32Array(oldRawEntries);
let newEntries = new Uint32Array(oldEntries.length + 1);
newEntries.set(oldEntries, 0);
newEntries[newEntries.length - 1] = value;
map.set(key, newEntries.buffer);
}
}
private static _read(map: Map<string, ArrayBuffer>, key: string): number[] {
let arrBuff = map.get(key);
if (typeof arrBuff === 'undefined') {
return null;
}
let arr = new Uint32Array(arrBuff);
let result: number[] = [];
for (let i = 0, len = arr.length; i < len; i++) {
result[i] = arr[i];
}
return result;
}
private _addToLookupMap(item: NormalizedKeybindingItem): void {
if (!item.command) {
return;
}
this._lookupMap[item.command] = this._lookupMap[item.command] || [];
this._lookupMap[item.command].push(item);
KeybindingResolver._push(this._lookupMap, item.command, item.keybinding);
}
public getDefaultBoundCommands(): IBoundCommands {
......@@ -267,14 +292,12 @@ export class KeybindingResolver {
}
public lookupKeybinding(commandId: string): Keybinding[] {
let rawPossibleTriggers = this._lookupMap[commandId];
if (!rawPossibleTriggers) {
let possibleTriggers = KeybindingResolver._read(this._lookupMap, commandId);
if (!possibleTriggers) {
return [];
}
let possibleTriggers = rawPossibleTriggers.map(possibleTrigger => possibleTrigger.keybinding);
let remove = this._lookupMapUnreachable[commandId];
let remove = KeybindingResolver._read(this._lookupMapUnreachable, commandId);
if (remove) {
possibleTriggers = possibleTriggers.filter((possibleTrigger) => {
return remove.indexOf(possibleTrigger) === -1;
......
......@@ -493,7 +493,7 @@ suite('Keybinding Service', () => {
let lookupResult = resolver.lookupKeybinding(commandId);
assert.equal(lookupResult.length, expectedKeys.length, 'Length mismatch @ commandId ' + commandId + '; GOT: ' + JSON.stringify(lookupResult, null, '\t'));
for (let i = 0, len = lookupResult.length; i < len; i++) {
assert.equal(lookupResult[i].value, expectedKeys[i]);
assert.equal(lookupResult[i].value, expectedKeys[i], 'value mismatch @ commandId ' + commandId);
}
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册