introducing getEqualHashCode

This commit is contained in:
Danny Yoo 2011-11-04 13:28:08 -04:00
parent fd28c199e9
commit 07b44b2239
17 changed files with 224 additions and 9 deletions

View File

@ -93,7 +93,8 @@
'make-hash 'make-hash
'make-hasheqv 'make-hasheqv
'make-hasheq 'make-hasheq
'hash-ref
'hash-set!
)) ))
(define-predicate KernelPrimitiveName? KernelPrimitiveName) (define-predicate KernelPrimitiveName? KernelPrimitiveName)

View File

@ -59,6 +59,15 @@
return ((other instanceof Box) && return ((other instanceof Box) &&
baselib.equality.equals(this.val, other.val, aUnionFind)); baselib.equality.equals(this.val, other.val, aUnionFind));
}; };
Box.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("Box");
k = baselib.hashes.hashMix(k);
k += baselib.hashes.getEqualHashCode(this.val, depth);
k = baselib.hashes.hashMix(k);
return k;
};
var makeBox = function(x) { var makeBox = function(x) {
return new Box(x, true); return new Box(x, true);

View File

@ -60,6 +60,16 @@
return true; return true;
}; };
Bytes.prototype.hashCode = function(depth) {
var i;
var k = baselib.hashes.getEqualHashCode('Bytes');
for (i = 0; i < n; i++) {
k += this.bytes[i];
k = baselib.hashes.hashMix(k);
}
return k;
};
Bytes.prototype.toString = function(cache) { Bytes.prototype.toString = function(cache) {
var ret = [], i; var ret = [], i;

View File

@ -67,7 +67,12 @@
return other instanceof Char && this.val == other.val; return other instanceof Char && this.val == other.val;
}; };
Char.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode('Char');
k += this.val.charCodeAt(0);
k = baselib.hashes.hashMix(k);
return k;
};
exports.Char = Char; exports.Char = Char;

View File

@ -61,7 +61,7 @@
return new WhalesongHashtable( return new WhalesongHashtable(
"hash", "hash",
function (x) { function (x) {
return baselib.format.toWrittenString(x); return getEqualHashCode(x);
}, },
function (x, y) { function (x, y) {
return baselib.equality.equals(x, y, new baselib.UnionFind()); return baselib.equality.equals(x, y, new baselib.UnionFind());
@ -72,7 +72,7 @@
return new WhalesongHashtable( return new WhalesongHashtable(
"hasheqv", "hasheqv",
function (x) { function (x) {
return baselib.format.toWrittenString(x); return getEqHashCode(x);
}, },
baselib.equality.eqv); baselib.equality.eqv);
}; };
@ -134,7 +134,14 @@
return true; return true;
}; };
WhalesongHashtable.prototype.hashCode = function(depth) {
var k = getEqualHashCode(this.type);
var keys = this.hash.keys(), i;
for (i = 0; i < keys.length; i++) {
k += hashMix(getEqualHashCode(this.hash.get(keys[i]), depth));
}
return hashMix(k);
};
@ -159,9 +166,63 @@
}; };
// Arbitrary magic number. We have to cut off the hashing at some point.
var MAX_HASH_DEPTH = 128;
// Returns a JavaScript number.
var getEqualHashCode = function (x, depth) {
var i, t, k = 0;
if (depth === undefined) { depth = 0; }
if (depth > MAX_HASH_DEPTH) { return 0; }
if (baselib.numbers.isNumber(x)) {
return hashMix(baselib.numbers.toFixnum(x));
}
if (baselib.strings.isString(x)) {
t = x.toString();
for (i = 0; i < t.length; i++) {
k += t.charCodeAt(i);
k = hashMix(k);
}
return k;
}
if (x === undefined || x === null) {
return 1;
}
if (typeof (x) === 'object' && typeof (y) === 'object' &&
typeof(x.hashCode) === 'function') {
return x.hashCode(depth + 1);
}
return 0;
};
// Does some weird math on k. Grabbed from Racket's implementation of hashes.
// References to: http://www.burtleburtle.net/bob/hash/doobs.html
var hashMix = function(k) {
k += (k << 10);
k ^= (k >> 6);
return k;
};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
exports.getEqHashCode = getEqHashCode; exports.getEqHashCode = getEqHashCode;
exports.getEqualHashCode = getEqualHashCode;
exports.hashMix = hashMix;
exports.makeEqHashCode = makeEqHashCode; exports.makeEqHashCode = makeEqHashCode;
exports.makeLowLevelEqHash = makeLowLevelEqHash; exports.makeLowLevelEqHash = makeLowLevelEqHash;

View File

@ -27,6 +27,13 @@
return other instanceof Keyword && return other instanceof Keyword &&
this.val === other.val; this.val === other.val;
}; };
Keyword.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("Keyword");
k += baselib.hashes.getEqualHashCode(this.val, depth);
k = baselib.hashes.hashMix(k);
return k;
};
Keyword.prototype.toString = function (cache) { Keyword.prototype.toString = function (cache) {

View File

@ -20,6 +20,11 @@
return other instanceof Empty; return other instanceof Empty;
}; };
Empty.prototype.hashCode = function(depth) {
return baselib.hashes.getEqualHashCode("empty");
};
Empty.prototype.reverse = function () { Empty.prototype.reverse = function () {
return this; return this;
}; };
@ -85,6 +90,16 @@
baselib.equality.equals(this.rest, other.rest, aUnionFind)); baselib.equality.equals(this.rest, other.rest, aUnionFind));
}; };
Cons.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("Cons");
k += baselib.hashes.getEqualHashCode(this.first);
k = baselib.hashes.hashMix(k);
k += baselib.hashes.getEqualHashCode(this.rest);
k = baselib.hashes.hashMix(k);
return k;
};
// Cons.append: (listof X) -> (listof X) // Cons.append: (listof X) -> (listof X)
Cons.prototype.append = function (b) { Cons.prototype.append = function (b) {

View File

@ -16,6 +16,20 @@
return "#<path:" + String(this.path) + ">"; return "#<path:" + String(this.path) + ">";
}; };
Path.prototype.equals = function(other, aUnionFind) {
return (other instanceof Path &&
this.path === other.path);
};
Path.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("path");
k += baselib.hashes.getEqualHashCode(this.path, depth);
k = baselib.hashes.hashMix(k);
return k;
};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
var makePath = function (p) { var makePath = function (p) {

View File

@ -43,6 +43,12 @@
baselib.equality.equals(this.val, other.val, aUnionFind)); baselib.equality.equals(this.val, other.val, aUnionFind));
}; };
Placeholder.prototype.hashCode = function(depth) {
var k = baselib.hashes.hashCode("Placeholder");
k += baselib.hashes.hashCode(this.val, depth);
return baselib.hashes.hashMix(k);
};
var makePlaceholder = function(v) { var makePlaceholder = function(v) {
return new Placeholder(v); return new Placeholder(v);

View File

@ -61,6 +61,7 @@
// Exceptions and error handling. // Exceptions and error handling.
var raise = baselib.exceptions.raise; var raise = baselib.exceptions.raise;
var raiseContractError = baselib.exceptions.raiseContractError;
var raiseArgumentTypeError = baselib.exceptions.raiseArgumentTypeError; var raiseArgumentTypeError = baselib.exceptions.raiseArgumentTypeError;
var raiseArityMismatchError = baselib.exceptions.raiseArityMismatchError; var raiseArityMismatchError = baselib.exceptions.raiseArityMismatchError;
@ -2558,13 +2559,14 @@
} else { } else {
if (M.a === 2) { if (M.a === 2) {
raiseContractError( raiseContractError(
plt.baselib.format("hash-ref: no value found for key: ~e", M,
baselib.format.format("hash-ref: no value found for key: ~e",
[key])); [key]));
} else { } else {
M.p = thunk; M.p = thunk;
M.e.length -= M.a; M.e.length -= M.a;
M.a = 0; M.a = 0;
baselib.functions.rawApply(); baselib.functions.rawApply(M);
} }
} }
}); });

View File

@ -107,6 +107,10 @@
return this.toString() === other.toString(); return this.toString() === other.toString();
}; };
Str.prototype.hashCode = function(depth) {
return baselib.hashes.getEqualHashCode(this.toString());
};
Str.prototype.set = function (i, c) { Str.prototype.set = function (i, c) {
this.chars[i] = c; this.chars[i] = c;

View File

@ -60,6 +60,18 @@
return true; return true;
}; };
Struct.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode(this.name);
var i;
k = baselib.hashes.hashMix(k);
for (i = 0; i < this._fields.length; i++) {
k += baselib.hashes.getEqualHashCode(this._fields[i]);
k = baselib.hashes.hashMix(k);
}
return k;
};
Struct.prototype.type = Struct; Struct.prototype.type = Struct;
@ -101,6 +113,13 @@
return this === other; return this === other;
}; };
StructType.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("StructType");
k = baselib.hashes.hashMix(k);
k += baselib.hashes.getEqualHashCode(this.name);
k = baselib.hashes.hashMix(k);
return k;
};

View File

@ -30,6 +30,14 @@
return other instanceof Symbol && return other instanceof Symbol &&
this.val === other.val; this.val === other.val;
}; };
Symbol.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("Symbol");
k = baselib.hashes.hashMix(k);
k += baselib.hashes.getEqualHashCode(this.val);
k = baselib.hashes.hashMix(k);
return k;
};
Symbol.prototype.toString = function (cache) { Symbol.prototype.toString = function (cache) {

View File

@ -56,6 +56,17 @@
} }
}; };
Vector.prototype.hashCode = function(depth) {
var k = baselib.hashes.getEqualHashCode("Vector");
var i;
k = baselib.hashes.hashMix(k);
for (i = 0; i < this.elts.length; i++) {
k += baselib.hashes.getEqualHashCode(this.elts[i], depth);
k = baselib.hashes.hashMix(k);
}
return k;
};
Vector.prototype.toList = function () { Vector.prototype.toList = function () {
var ret = baselib.lists.EMPTY, i; var ret = baselib.lists.EMPTY, i;
for (i = this.length() - 1; i >= 0; i--) { for (i = this.length() - 1; i >= 0; i--) {

View File

@ -153,7 +153,8 @@
make-hash make-hash
make-hasheqv make-hasheqv
make-hasheq make-hasheq
hash-ref
hash-set!
;; Kernel inlinable ;; Kernel inlinable

View File

@ -0,0 +1,14 @@
#lang planet dyoo/whalesong/base
;; boxes
;; bytes
;; chars
;; hashes
;; keywords
;; lists
;; paths
;; placeholders
;; strings
;; structs
;; symbols
;; vectors

View File

@ -33,4 +33,32 @@
(make-hasheq '((1 . one) (make-hasheq '((1 . one)
(2 . two) (2 . two)
(3 . three) (3 . three)
(4 . four))) (4 . four)))
(hash-ref (make-hash '((1 . one)
(2 . two)
(3 . three)))
1)
(hash-ref (make-hash '((1 . one)
(2 . two)
(3 . three)))
4
(lambda () 'not-found))
(define words '("this" "is" "a" "test" "that" "is" "only" "a" "test!"))
(define ht (make-hash))
(for-each (lambda (w)
(hash-set! ht
w
(add1 (hash-ref ht w (lambda () 0)))))
words)
(hash-ref ht "this")
(hash-ref ht "is")
(hash-ref ht "a")
(hash-ref ht "test")
(hash-ref ht "that")
(hash-ref ht "only")
(hash-ref ht "test!")