[gnome-shell] Add a new Hash module
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] Add a new Hash module
- Date: Thu, 31 Jan 2013 12:22:29 +0000 (UTC)
commit daf8be9f7838bcfa3fe8b032be947a4fa73f06c6
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sun Nov 4 15:50:02 2012 +0100
Add a new Hash module
A simple implementation of the ES6 Map proposal, internally
done as a hash table, using System.addressOf() to support keys that
are arbitrary objects.
Should help replacing linear searches in various places around the shell.
https://bugzilla.gnome.org/show_bug.cgi?id=685926
js/Makefile.am | 1 +
js/misc/hash.js | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 142 insertions(+), 0 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index 29187da..323cd1b 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -28,6 +28,7 @@ nobase_dist_js_DATA = \
misc/extensionUtils.js \
misc/fileUtils.js \
misc/gnomeSession.js \
+ misc/hash.js \
misc/history.js \
misc/jsParse.js \
misc/loginManager.js \
diff --git a/js/misc/hash.js b/js/misc/hash.js
new file mode 100644
index 0000000..19d4df6
--- /dev/null
+++ b/js/misc/hash.js
@@ -0,0 +1,141 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Lang = imports.lang;
+const System = imports.system;
+
+const Params = imports.misc.params;
+
+// This is an implementation of EcmaScript SameValue algorithm,
+// which returns true if two values are not observably distinguishable.
+// It was taken from http://wiki.ecmascript.org/doku.php?id=harmony:egal
+//
+// In the future, we may want to use the 'is' operator instead.
+function _sameValue(x, y) {
+ if (x === y) {
+ // 0 === -0, but they are not identical
+ return x !== 0 || 1 / x === 1 / y;
+ }
+
+ // NaN !== NaN, but they are identical.
+ // NaNs are the only non-reflexive value, i.e., if x !== x,
+ // then x is a NaN.
+ // isNaN is broken: it converts its argument to number, so
+ // isNaN("foo") => true
+ return x !== x && y !== y;
+}
+
+const _hashers = {
+ object: function(o) { return o ? System.addressOf(o) : 'null'; },
+ function: function(f) { return System.addressOf(f); },
+ string: function(s) { return s; },
+ number: function(n) { return String(n); },
+ undefined: function() { return 'undefined'; },
+};
+
+/* Map is meant to be similar in usage to ES6 Map, which is
+ described at http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets,
+ without requiring more than ES5 + Gjs extensions.
+
+ Known differences from other implementations:
+ Polyfills around the web usually implement HashMaps for
+ primitive values and reversed WeakMaps for object keys,
+ but we want real maps with real O(1) semantics in all cases,
+ and the easiest way is to have different hashers for different
+ types.
+
+ Known differences from the ES6 specification:
+ - Map is a Lang.Class, not a ES6 class, so inheritance,
+ prototype, sealing, etc. work differently.
+ - items(), keys() and values() don't return iterators,
+ they return actual arrays, so they incur a full copy everytime
+ they're called, and they don't see changes if you mutate
+ the table while iterating
+ (admittedly, the ES6 spec is a bit unclear on this, and
+ the reference code would just blow up)
+*/
+const Map = new Lang.Class({
+ Name: 'Map',
+
+ _init: function(iterable) {
+ this._pool = { };
+
+ if (iterable) {
+ for (let i = 0; i < iterable.length; i++) {
+ let [key, value] = iterable[i];
+ this.set(key, value);
+ }
+ }
+ },
+
+ _hashKey: function(key) {
+ let type = typeof(key);
+ return type + ':' + _hashers[type](key);
+ },
+
+ _internalGet: function(key) {
+ let hash = this._hashKey(key);
+ let node = this._pool[hash];
+
+ if (node && _sameValue(node.key, key))
+ return [true, node.value];
+ else
+ return [false, null];
+ },
+
+ get: function(key) {
+ return this._internalGet(key)[1];
+ },
+
+ has: function(key) {
+ return this._internalGet(key)[0];
+ },
+
+ set: function(key, value) {
+ let hash = this._hashKey(key);
+ let node = this._pool[hash];
+
+ if (node) {
+ node.key = key;
+ node.value = value;
+ } else {
+ this._pool[hash] = { key: key, value: value };
+ }
+ },
+
+ delete: function(key) {
+ let hash = this._hashKey(key);
+ let node = this._pool[hash];
+
+ if (node && _sameValue(node.key, key)) {
+ delete this._pool[hash];
+ return [node.key, node.value];
+ } else {
+ return [null, null];
+ }
+ },
+
+ keys: function() {
+ let pool = this._pool;
+ return Object.getOwnPropertyNames(pool).map(function(hash) {
+ return pool[hash].key;
+ });
+ },
+
+ values: function() {
+ let pool = this._pool;
+ return Object.getOwnPropertyNames(pool).map(function(hash) {
+ return pool[hash].value;
+ });
+ },
+
+ items: function() {
+ let pool = this._pool;
+ return Object.getOwnPropertyNames(pool).map(function(hash) {
+ return [pool[hash].key, pool[hash].value];
+ });
+ },
+
+ size: function() {
+ return Object.getOwnPropertyNames(this._pool).length;
+ },
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]