summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2015-04-28 16:16:08 -0700
committerMark Spruiell <mes@zeroc.com>2015-04-28 16:16:08 -0700
commit5e65b73b909c43f06a4e8bd4c952388a2be55f7d (patch)
tree4b95d556ce378c0d0fbf5638c7d1b5ff041403bd
parentFixed typo in CHANGELOG-3.6.md (diff)
downloadice-5e65b73b909c43f06a4e8bd4c952388a2be55f7d.tar.bz2
ice-5e65b73b909c43f06a4e8bd4c952388a2be55f7d.tar.xz
ice-5e65b73b909c43f06a4e8bd4c952388a2be55f7d.zip
ICE-6454 - add keys() method to JS HashMap
-rwxr-xr-xjs/allTests.py1
-rw-r--r--js/src/Ice/.gitignore1
-rw-r--r--js/src/Ice/HashMap.js97
-rw-r--r--js/test/Ice/hashmap/Client.js239
-rw-r--r--js/test/Ice/hashmap/run.js10
-rwxr-xr-xjs/test/Ice/hashmap/run.py23
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()