dict: Replace with Map.

Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
This commit is contained in:
Anders Kaseorg 2020-02-03 00:39:58 -08:00 committed by Tim Abbott
parent 7cc16757aa
commit 2868b7c3e3
13 changed files with 14 additions and 253 deletions

View File

@ -213,7 +213,6 @@
"globals": {
"$": false,
"ClipboardJS": false,
"Dict": false,
"FetchStatus": false,
"Filter": false,
"Handlebars": false,

View File

@ -1,8 +1,6 @@
set_global('$', global.make_zjquery());
set_global('blueslip', global.make_zblueslip());
const Dict = zrequire('dict').Dict;
let filter_key_handlers;
const _page_params = {
@ -382,7 +380,7 @@ run_test('PM_update_dom_counts', () => {
li.set_find_results('.count', count);
count.set_parents_result('li', li);
const counts = new Dict();
const counts = new Map();
counts.set(pm_key, 5);
li.addClass('user_sidebar_entry');
@ -407,7 +405,7 @@ run_test('group_update_dom_counts', () => {
li.set_find_results('.count', count);
count.set_parent(li);
const counts = new Dict();
const counts = new Map();
counts.set(pm_key, 5);
li.addClass('group-pms-sidebar-entry');

View File

@ -1,171 +0,0 @@
set_global('blueslip', global.make_zblueslip());
const Dict = zrequire('dict').Dict;
run_test('basic', () => {
const d = new Dict();
assert.equal(d.size, 0);
assert.deepEqual(Array.from(d.keys()), []);
d.set('foo', 'bar');
assert.equal(d.get('foo'), 'bar');
assert.notEqual(d.size, 0);
d.set('foo', 'baz');
assert.equal(d.get('foo'), 'baz');
assert.equal(d.size, 1);
d.set('bar', 'qux');
assert.equal(d.get('foo'), 'baz');
assert.equal(d.get('bar'), 'qux');
assert.equal(d.size, 2);
assert.equal(d.has('bar'), true);
assert.equal(d.has('baz'), false);
assert.deepEqual(Array.from(d.keys()), ['foo', 'bar']);
assert.deepEqual(Array.from(d.values()), ['baz', 'qux']);
assert.deepEqual(Array.from(d), [['foo', 'baz'], ['bar', 'qux']]);
d.delete('bar');
assert.equal(d.has('bar'), false);
assert.strictEqual(d.get('bar'), undefined);
assert.deepEqual(Array.from(d.keys()), ['foo']);
const val = ['foo'];
const res = d.set('abc', val);
assert.strictEqual(res, d);
});
run_test('undefined_keys', () => {
blueslip.clear_test_data();
blueslip.set_test_data('error', 'Tried to call a Dict method with an undefined key.');
const d = new Dict();
assert.equal(d.has(undefined), false);
assert.strictEqual(d.get(undefined), undefined);
assert.equal(blueslip.get_test_logs('error').length, 2);
});
run_test('non-strings', () => {
blueslip.clear_test_data();
blueslip.set_test_data('error', 'Tried to call a Dict method with a non-string.');
const d = new Dict();
d.set('17', 'value');
assert.equal(d.get(17), 'value');
assert.equal(blueslip.get_test_logs('error').length, 1);
});
run_test('restricted_keys', () => {
const d = new Dict();
assert.equal(d.has('__proto__'), false);
assert.equal(d.has('hasOwnProperty'), false);
assert.equal(d.has('toString'), false);
assert.strictEqual(d.get('__proto__'), undefined);
assert.strictEqual(d.get('hasOwnProperty'), undefined);
assert.strictEqual(d.get('toString'), undefined);
d.set('hasOwnProperty', function () {return true;});
assert.equal(d.has('blah'), false);
d.set('__proto__', 'foo');
d.set('foo', 'bar');
assert.equal(d.get('foo'), 'bar');
});
run_test('construction', () => {
const d1 = new Dict();
assert.deepEqual(Array.from(d1), []);
const d2 = new Dict();
d2.set('foo', 'bar');
d2.set('baz', 'qux');
assert.deepEqual(Array.from(d2), [['foo', 'bar'], ['baz', 'qux']]);
});
run_test('each', () => {
const d = new Dict();
d.set('apple', 40);
d.set('banana', 50);
d.set('carrot', 60);
let unseen_keys = Array.from(d.keys());
let cnt = 0;
for (const [k, v] of d) {
assert.equal(v, d.get(k));
unseen_keys = _.without(unseen_keys, k);
cnt += 1;
}
assert.equal(cnt, d.size);
assert.equal(unseen_keys.length, 0);
});
run_test('num_items', () => {
const d = new Dict();
assert.equal(d.size, 0);
d.set('foo', 1);
assert.equal(d.size, 1);
d.set('foo', 2);
assert.equal(d.size, 1);
d.set('bar', 1);
assert.equal(d.size, 2);
d.delete('foo');
assert.equal(d.size, 1);
});
/*
run_test('benchmark', () => {
const d = new Dict();
const n = 5000;
const t1 = new Date().getTime();
_.each(_.range(n), (i) => {
d.set(i, i);
});
_.each(_.range(n), (i) => {
d.get(i, i);
});
const t2 = new Date().getTime();
const elapsed = t2 - t1;
console.log('elapsed (milli)', elapsed);
console.log('per (micro)', 1000 * elapsed / n);
});
*/
run_test('clear', () => {
const d = new Dict();
function populate() {
d.set('foo', 1);
assert.equal(d.get('foo'), 1);
d.set('bar', 2);
assert.equal(d.get('bar'), 2);
}
populate();
assert.equal(d.size, 2);
d.clear();
assert.equal(d.get('foo'), undefined);
assert.equal(d.get('bar'), undefined);
assert.equal(d.size, 0);
// make sure it still works after clearing
populate();
assert.equal(d.size, 2);
});

View File

@ -1,5 +1,4 @@
const render_group_pms = require('../templates/group_pms.hbs');
const Dict = require('./dict').Dict;
/*
Helpers for detecting user activity and managing user idle states
@ -27,7 +26,7 @@ exports.client_is_active = document.hasFocus && document.hasFocus();
// server-initiated reload as user activity.
exports.new_user_input = true;
const huddle_timestamps = new Dict();
const huddle_timestamps = new Map();
function update_pm_count_in_dom(count_span, value_span, count) {
const li = count_span.parents('li');

View File

@ -28,7 +28,6 @@ import "../keydown_util.js";
import "../lightbox_canvas.js";
import "../rtl.js";
import "../lazy_set.js";
import "../dict.ts";
import "../int_dict.ts";
import "../fold_dict.ts";
import "../scroll_util.js";

View File

@ -1,55 +0,0 @@
export class Dict<V> {
private _items: Map<string, V> = new Map();
get(key: string): V | undefined {
return this._items.get(this._munge(key));
}
set(key: string, value: V): Dict<V> {
this._items.set(this._munge(key), value);
return this;
}
has(key: string): boolean {
return this._items.has(this._munge(key));
}
delete(key: string): void {
this._items.delete(this._munge(key));
}
keys(): Iterator<string> {
return this._items.keys();
}
values(): Iterator<V> {
return this._items.values();
}
[Symbol.iterator](): Iterator<[string, V]> {
return this._items.entries();
}
get size(): number {
return this._items.size;
}
clear(): void {
this._items.clear();
}
// Convert keys to strings and handle undefined.
private _munge(key: string): string | undefined {
if (key === undefined) {
blueslip.error("Tried to call a Dict method with an undefined key.");
return undefined;
}
if (typeof key !== 'string') {
blueslip.error("Tried to call a Dict method with a non-string.");
key = (key as object).toString();
}
return key;
}
}

View File

@ -1,5 +1,3 @@
const Dict = require('./dict').Dict;
let current_filter;
exports.reset_current_filter = function () {
@ -47,8 +45,8 @@ exports.search_string = function () {
// Collect operators which appear only once into an object,
// and discard those which appear more than once.
function collect_single(operators) {
const seen = new Dict();
const result = new Dict();
const seen = new Map();
const result = new Map();
for (const elem of operators) {
const key = elem.operator;

View File

@ -16,7 +16,7 @@ let my_user_id;
// We have an init() function so that our automated tests
// can easily clear data.
exports.init = function () {
// The following three Dicts point to the same objects
// The following three dicts point to the same objects
// (all people we've seen), but people_dict can have duplicate
// keys related to email changes. We want to deprecate
// people_dict over time and always do lookups by user_id.

View File

@ -1,6 +1,5 @@
const emoji_codes = require("../generated/emoji/emoji_codes.json");
const render_message_reaction = require('../templates/message_reaction.hbs');
const Dict = require('./dict').Dict;
exports.view = {}; // function namespace
@ -399,7 +398,7 @@ exports.get_emojis_used_by_user_for_message_id = function (message_id) {
};
exports.get_message_reactions = function (message) {
const message_reactions = new Dict();
const message_reactions = new Map();
for (const reaction of message.reactions) {
const user_id = reaction.user.id;

View File

@ -1,8 +1,8 @@
const FoldDict = require('./fold_dict').FoldDict;
const IntDict = require('./int_dict').IntDict;
const topic_senders = new IntDict(); // key is stream-id, value is Dict
const stream_senders = new IntDict(); // key is stream-id, value is Dict
const topic_senders = new IntDict(); // key is stream-id, value is Map
const stream_senders = new IntDict(); // key is stream-id, value is Map
exports.process_message_for_senders = function (message) {
const stream_id = message.stream_id;

View File

@ -1,6 +1,4 @@
const Dict = require('./dict').Dict;
const load_func_dict = new Dict(); // group -> function
const load_func_dict = new Map(); // group -> function
const loaded_groups = new Set();
exports.get_group = function (section) {

View File

@ -1,10 +1,8 @@
const util = require("./util");
const Dict = require('./dict').Dict;
// See docs/subsystems/typing-indicators.md for details on typing indicators.
const typist_dct = new Dict();
const inbound_timer_dict = new Dict();
const typist_dct = new Map();
const inbound_timer_dict = new Map();
function to_int(s) {
return parseInt(s, 10);

View File

@ -1,5 +1,4 @@
const util = require("./util");
const Dict = require('./dict').Dict;
const FoldDict = require('./fold_dict').FoldDict;
const IntDict = require('./int_dict').IntDict;
@ -85,7 +84,7 @@ exports.unread_pm_counter = (function () {
const self = {};
const bucketer = make_bucketer({
KeyDict: Dict,
KeyDict: Map,
make_bucket: () => new Set(),
});
@ -131,7 +130,7 @@ exports.unread_pm_counter = (function () {
};
self.get_counts = function () {
const pm_dict = new Dict(); // Hash by user_ids_string -> count
const pm_dict = new Map(); // Hash by user_ids_string -> count
let total_count = 0;
for (const [user_ids_string, id_set] of bucketer) {
const count = id_set.size;