diff options
author | Mark Spruiell <mes@zeroc.com> | 2015-04-28 16:16:08 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2015-04-28 16:16:08 -0700 |
commit | 5e65b73b909c43f06a4e8bd4c952388a2be55f7d (patch) | |
tree | 4b95d556ce378c0d0fbf5638c7d1b5ff041403bd /js | |
parent | Fixed typo in CHANGELOG-3.6.md (diff) | |
download | ice-5e65b73b909c43f06a4e8bd4c952388a2be55f7d.tar.bz2 ice-5e65b73b909c43f06a4e8bd4c952388a2be55f7d.tar.xz ice-5e65b73b909c43f06a4e8bd4c952388a2be55f7d.zip |
ICE-6454 - add keys() method to JS HashMap
Diffstat (limited to 'js')
-rwxr-xr-x | js/allTests.py | 1 | ||||
-rw-r--r-- | js/src/Ice/.gitignore | 1 | ||||
-rw-r--r-- | js/src/Ice/HashMap.js | 97 | ||||
-rw-r--r-- | js/test/Ice/hashmap/Client.js | 239 | ||||
-rw-r--r-- | js/test/Ice/hashmap/run.js | 10 | ||||
-rwxr-xr-x | js/test/Ice/hashmap/run.py | 23 |
6 files changed, 342 insertions, 29 deletions
diff --git a/js/allTests.py b/js/allTests.py index 79d3941f631..940f797b41a 100755 --- a/js/allTests.py +++ b/js/allTests.py @@ -34,6 +34,7 @@ tests = [ ("Ice/exceptionsBidir", ["once"]), ("Ice/facets", ["core"]), ("Ice/facetsBidir", ["core"]), + ("Ice/hashmap", ["once"]), ("Ice/hold", ["core"]), ("Ice/inheritance", ["once"]), ("Ice/inheritanceBidir", ["once"]), diff --git a/js/src/Ice/.gitignore b/js/src/Ice/.gitignore index 2e8a310bf0b..335e1ee1815 100644 --- a/js/src/Ice/.gitignore +++ b/js/src/Ice/.gitignore @@ -1,6 +1,7 @@ # Ignore generated files BuiltinSequences.js Connection.js +ConnectionInfo.js Current.js Endpoint.js EndpointInfo.js diff --git a/js/src/Ice/HashMap.js b/js/src/Ice/HashMap.js index 6da04397e53..a662d884a9f 100644 --- a/js/src/Ice/HashMap.js +++ b/js/src/Ice/HashMap.js @@ -9,7 +9,7 @@ var Ice = require("../Ice/ModuleRegistry").Ice; var __M = Ice.__M; -__M.require(module, ["../Ice/Class", "../Ice/StringUtil"]); +__M.require(module, ["../Ice/Class", "../Ice/StringUtil", "../Ice/UUID"]); var StringUtil = Ice.StringUtil; function setInternal(map, key, value, hash, index) @@ -109,26 +109,28 @@ var HashMap = Ice.Class({ }, set: function(key, value) { - var hash = this.computeHash(key); + var r = this.computeHash(key); // Returns an object with key,hash members. - var index = this.hashIndex(hash, this._table.length); + var index = this.hashIndex(r.hash, this._table.length); - return setInternal(this, key, value, hash, index); + return setInternal(this, r.key, value, r.hash, index); }, get: function(key) { - var e = this.findEntry(key, this.computeHash(key)); + var r = this.computeHash(key); // Returns an object with key,hash members. + var e = this.findEntry(r.key, r.hash); return e !== undefined ? e._value : undefined; }, has: function(key) { - return this.findEntry(key, this.computeHash(key)) !== undefined; + var r = this.computeHash(key); // Returns an object with key,hash members. + return this.findEntry(r.key, r.hash) !== undefined; }, delete: function(key) { - var hash = this.computeHash(key); + var r = this.computeHash(key); // Returns an object with key,hash members. - var index = this.hashIndex(hash, this._table.length); + var index = this.hashIndex(r.hash, this._table.length); // // Search for an entry with the same key. @@ -136,7 +138,7 @@ var HashMap = Ice.Class({ var prev = null; for(var e = this._table[index]; e !== null; e = e._nextInBucket) { - if(e._hash === hash && this.keysEqual(key, e._key)) + if(e._hash === r.hash && this.keysEqual(r.key, e._key)) { // // Found a match. @@ -197,6 +199,26 @@ var HashMap = Ice.Class({ fn.call(obj, e._key, e._value); } }, + keys: function() + { + var k = []; + var i = 0; + for(var e = this._head; e !== null; e = e._next) + { + k[i++] = e._key; + } + return k; + }, + values: function() + { + var v = []; + var i = 0; + for(var e = this._head; e !== null; e = e._next) + { + v[i++] = e._value; + } + return v; + }, equals: function(other, valuesEqual) { if(other === null || !(other instanceof HashMap) || this._size !== other._size) @@ -237,16 +259,6 @@ var HashMap = Ice.Class({ // // Create a new table entry. // - /* - var e = - { - key: key, - value: value, - prev: null, - next: null, - _hash: hash - } - */ var e = Object.create(null, { "key": { enumerable: true, @@ -352,30 +364,55 @@ var HashMap = Ice.Class({ }, computeHash: function(v) { + if(v === 0 || v === -0) + { + return {key:0, hash:0}; + } + + if(v === null) + { + if(HashMap._null === null) + { + var uuid = Ice.generateUUID(); + HashMap._null = {key:uuid, hash:StringUtil.hashCode(uuid)}; + } + return HashMap._null; + } + + if(v === undefined) + { + throw new Error("cannot compute hash for undefined value"); + } + if(typeof(v.hashCode) === "function") { - return v.hashCode(); + return {key:v, hash:v.hashCode()}; } - var hash = 0; var type = typeof(v); if(type === "string" || v instanceof String) { - hash = StringUtil.hashCode(v); + return {key:v, hash:StringUtil.hashCode(v)}; } else if(type === "number" || v instanceof Number) { - hash = v.toFixed(0); + if(isNaN(v)) + { + if(HashMap._nan === null) + { + var uuid = Ice.generateUUID(); + HashMap._nan = {key:uuid, hash:StringUtil.hashCode(uuid)}; + } + return HashMap._nan; + } + return {key:v, hash:v.toFixed(0)}; } else if(type === "boolean" || v instanceof Boolean) { - hash = v ? 1 : 0; - } - else if(v !== null) - { - throw "cannot compute hash for value of type " + type; + return {key:v, hash:v ? 1 : 0}; } - return hash; + + throw new Error("cannot compute hash for value of type " + type); }, keysEqual: function(k1, k2) { @@ -386,6 +423,8 @@ Ice.HashMap = HashMap; HashMap.compareEquals = compareEquals; HashMap.compareIdentity = compareIdentity; +HashMap._null = null; +HashMap._nan = null; var prototype = HashMap.prototype; diff --git a/js/test/Ice/hashmap/Client.js b/js/test/Ice/hashmap/Client.js new file mode 100644 index 00000000000..96c025b3765 --- /dev/null +++ b/js/test/Ice/hashmap/Client.js @@ -0,0 +1,239 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +(function(module, require, exports) +{ + var Ice = require("ice").Ice; + + var Promise = Ice.Promise; + + var fill = function(arr, val) + { + for(var i = 0; i < arr.length; ++i) + { + arr[i] = val; + } + }; + + var testKeys = function(keys, keyComparator, valueComparator) + { + var test = function(b) + { + if(!b) + { + throw new Error("test failed"); + } + }; + + var h = new Ice.HashMap(keyComparator, valueComparator); + for(var i = 0; i < keys.length; ++i) + { + h.set(keys[i], i); + } + + // + // Test the keys. + // + for(var i = 0; i < keys.length; ++i) + { + test(h.has(keys[i])); + test(h.get(keys[i]) === i); + test(h.delete(keys[i]) === i); + test(!h.has(keys[i])); + h.set(keys[i], i); + test(h.has(keys[i])); + } + + // + // Use an array to keep track of whether we've encountered all entries. + // + var a = []; + a.length = keys.length; + + // + // Test the keys() method. + // + fill(a, false); + var k = h.keys(); + test(k.length === keys.length); + for(var i = 0; i < k.length; ++i) + { + var p = keys.indexOf(k[i]); + test(p != -1); + a[p] = true; + } + test(a.indexOf(false) === -1); + + // + // Test the values() method. + // + fill(a, false); + var v = h.values(); + test(v.length === keys.length); + for(var i = 0; i < v.length; ++i) + { + a[v[i]] = true; + } + test(a.indexOf(false) === -1); + + // + // Test the forEach() method. + // + fill(a, false); + h.forEach(function(key, val) + { + test(keys[val] === key); + a[val] = true; + }); + test(a.indexOf(false) === -1); + + // + // Test the clone() & equals() methods. + // + var h2 = h.clone(); + test(h2.equals(h)); + + // + // Test the clear() method. + // + h.clear(); + test(h.size === 0); + }; + + var allTests = function(out) + { + var p = new Ice.Promise(); + var test = function(b) + { + if(!b) + { + try + { + throw new Error("test failed"); + } + catch(err) + { + p.fail(err); + throw err; + } + } + }; + + Promise.try( + function() + { + out.write("testing Ice.HashMap... "); + + var h = new Ice.HashMap(); + + // + // Test null key. + // + h.set(null, 1); + test(h.has(null)); + test(h.get(null) === 1); + h.set(null, 2); + test(h.get(null) === 2); + test(h.delete(null) === 2); + test(!h.has(null)); + + // + // Test NaN key. + // + h.set(NaN, 1); + test(h.has(NaN)); + test(h.has(-NaN)); + test(h.get(NaN) === 1); + test(h.get(-NaN) === 1); + h.set(NaN, 2); + test(h.get(NaN) === 2); + test(h.delete(NaN) === 2); + test(!h.has(NaN)); + + // + // Test zero key. + // + h.set(0, 1); + test(h.has(0)); + test(h.has(-0)); + test(h.get(0) === 1); + test(h.get(-0) === 1); + h.set(0, 2); + test(h.get(0) === 2); + test(h.delete(0) === 2); + test(!h.has(0)); + + // + // Test integer keys. + // + var k = []; + k.length = 1000; + for(var i = 0; i < k.length; ++i) + { + k[i] = i; + } + testKeys(k); + + // + // Test string keys. + // + k.length = 100; + for(var i = 0; i < k.length; ++i) + { + k[i] = Ice.generateUUID(); + } + testKeys(k); + + // + // Test boolean keys. + // + testKeys([true, false]); + + // + // Test object keys (with hashCode methods). + // + testKeys([Ice.OperationMode.Normal, Ice.OperationMode.Nonmutating, Ice.OperationMode.Idempotent]); + + // + // Test object keys (with hashCode methods and custom key comparator). + // + k.length = 10; + for(var i = 0; i < k.length; ++i) + { + k[i] = {key:i, hashCode:function() { return i; }}; + } + var eq = function(a, b) { return a.key === b.key; }; + testKeys(k, eq, eq); + + out.writeLine("ok"); + } + ).exception( + function(ex) + { + p.fail(ex); + } + ); + return p; + }; + + var run = function(out, id) + { + return Promise.try( + function() + { + return allTests(out); + } + ); + }; + exports.__test__ = run; + exports.__runServer__ = true; +} +(typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? module : undefined, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? require : window.Ice.__require, + typeof(global) !== "undefined" && typeof(global.process) !== "undefined" ? exports : window)); diff --git a/js/test/Ice/hashmap/run.js b/js/test/Ice/hashmap/run.js new file mode 100644 index 00000000000..7c2ffdcdd61 --- /dev/null +++ b/js/test/Ice/hashmap/run.js @@ -0,0 +1,10 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +require("../../Common/Common").run(module); diff --git a/js/test/Ice/hashmap/run.py b/js/test/Ice/hashmap/run.py new file mode 100755 index 00000000000..0a6abec46c2 --- /dev/null +++ b/js/test/Ice/hashmap/run.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# ********************************************************************** +# +# Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +import os, sys + +path = [ ".", "..", "../..", "../../..", "../../../..", "../../../../.." ] +head = os.path.dirname(sys.argv[0]) +if len(head) > 0: + path = [os.path.join(head, p) for p in path] +path = [os.path.abspath(p) for p in path if os.path.exists(os.path.join(p, "scripts", "TestUtil.py")) ] +if len(path) == 0: + raise RuntimeError("can't find toplevel directory!") +sys.path.append(os.path.join(path[0], "scripts")) +import TestUtil + +TestUtil.simpleTest() |