integrating the immutable hashes

This commit is contained in:
Danny Yoo 2011-11-07 17:39:21 -05:00
parent 93d7991960
commit 923d418840
7 changed files with 163 additions and 38 deletions

View File

@ -93,10 +93,13 @@
'make-hash 'make-hash
'make-hasheqv 'make-hasheqv
'make-hasheq 'make-hasheq
'make-immutable-hash
'make-immutable-hasheqv
'make-immutable-hasheq
'hash-ref 'hash-ref
'hash-set! 'hash-set!
'hash-set
'equal-hash-code 'equal-hash-code
)) ))
(define-predicate KernelPrimitiveName? KernelPrimitiveName) (define-predicate KernelPrimitiveName? KernelPrimitiveName)

View File

@ -258,6 +258,23 @@
var checkHash = makeCheckArgumentType( var checkHash = makeCheckArgumentType(
baselib.hashes.isHash, baselib.hashes.isHash,
'hash'); 'hash');
var checkHasheq = makeCheckArgumentType(
baselib.hashes.isHasheq,
'hash');
var checkHasheqv = makeCheckArgumentType(
baselib.hashes.isHasheqv,
'hash');
var checkMutableHash = makeCheckArgumentType(
function(x) { return baselib.hashes.isHash(x) && ! x.isImmutable()},
'mutable hash');
var checkImmutableHash = makeCheckArgumentType(
function(x) { return baselib.hashes.isHash(x) && x.isImmutable()},
'immutable hash');
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -298,5 +315,7 @@
exports.checkContinuationPromptTag = checkContinuationPromptTag; exports.checkContinuationPromptTag = checkContinuationPromptTag;
exports.checkExn = checkExn; exports.checkExn = checkExn;
exports.checkHash = checkHash; exports.checkHash = checkHash;
exports.checkImmutableHash = checkImmutableHash;
exports.checkMutableHash = checkMutableHash;
}(this.plt.baselib)); }(this.plt.baselib));

View File

@ -66,7 +66,6 @@
}; };
var makeEqHashtable = function() { var makeEqHashtable = function() {
return new WhalesongHashtable( return new WhalesongHashtable(
"hasheq", "hasheq",
@ -88,8 +87,21 @@
return new WhalesongHashtable( return new WhalesongHashtable(
"hasheqv", "hasheqv",
getEqvHashCode, getEqvHashCode,
baselib.equality.eqv, eqv,
new Hashtable(getEqvHashCode, baselib.equality.eqv)); new Hashtable(getEqvHashCode, eqv));
};
var makeImmutableEqHashtable = function() {
return makeEqHashtable().toImmutable();
};
var makeImmutableEqualHashtable = function() {
return makeEqualHashtable().toImmutable();
};
var makeImmutableEqvHashtable = function() {
return makeEqvHashtable().toImmutable();
}; };
@ -111,9 +123,6 @@
}; };
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Whalesong's Hashtables are a thin wrapper around the mutable Hashtable // Whalesong's Hashtables are a thin wrapper around the mutable Hashtable
// class to make it printable and equatable. // class to make it printable and equatable.
@ -187,10 +196,18 @@
this.hash.put(key, value); this.hash.put(key, value);
}; };
WhalesongHashtable.prototype.functionalPut = function(key, value) {
return this.toImmutable().functionalPut(key, value);
};
WhalesongHashtable.prototype.remove = function(key) { WhalesongHashtable.prototype.remove = function(key) {
this.hash.remove(key); this.hash.remove(key);
}; };
WhalesongHashtable.prototype.functionalRemove = function(key) {
return this.toImmutable().functionalRemove(key);
};
WhalesongHashtable.prototype.containsKey = function(key) { WhalesongHashtable.prototype.containsKey = function(key) {
return this.hash.containsKey(key); return this.hash.containsKey(key);
}; };
@ -199,6 +216,20 @@
return false; return false;
}; };
WhalesongHashtable.prototype.toImmutable = function() {
var keycmp = makeComparator(this.hash_function, this.equality_function)
var immutable = new WhalesongImmutableHashtable(
this.type,
this.hash_function,
this.equality_function,
LLRBTree.makeMap(keycmp));
var keys = this.hash.keys();
var i;
for (i = 0; i < keys.length; i++) {
immutable = immutable.functionalPut(keys[i], this.hash.get(keys[i]));
}
return immutable;
};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -206,12 +237,14 @@
// Whalesong's immutable hashtables are a thin wrapper around the // Whalesong's immutable hashtables are a thin wrapper around the
// llrbtree class to make it printable and equatable. // llrbtree class to make it printable and equatable.
// llrbtree comes from: https://github.com/dyoo/js-llrbtree // llrbtree comes from: https://github.com/dyoo/js-llrbtree
var WhalesongImmutableHashtable = function (type, hash_function, equality_function) { var WhalesongImmutableHashtable = function (type,
hash_function,
equality_function,
map) {
this.type = type; this.type = type;
this.hash_function = hash_function; this.hash_function = hash_function;
this.equality_function = equality_function; this.equality_function = equality_function;
this.keycmp = makeComparator(hash_function, equality_function); this.map = map;
this.map = LLRBTree.makeMap(keycmp);
}; };
WhalesongImmutableHashtable.prototype.toWrittenString = function (cache) { WhalesongImmutableHashtable.prototype.toWrittenString = function (cache) {
@ -249,7 +282,6 @@
if (litems.length !== ritems.length) { if (litems.length !== ritems.length) {
return false; return false;
} }
var i; var i;
for (i = 0; i < litems.length; i++) { for (i = 0; i < litems.length; i++) {
if (!(baselib.equality.equals(litems[i][0], ritems[i][0], aUnionFind))) { if (!(baselib.equality.equals(litems[i][0], ritems[i][0], aUnionFind))) {
@ -284,6 +316,10 @@
}; };
WhalesongImmutableHashtable.prototype.functionalPut = function(key, value) { WhalesongImmutableHashtable.prototype.functionalPut = function(key, value) {
return new WhalesongImmutableHashtable(this.type,
this.hash_function,
this.equality_function,
this.map.put(key, value));
}; };
WhalesongImmutableHashtable.prototype.remove = function(key) { WhalesongImmutableHashtable.prototype.remove = function(key) {
@ -291,7 +327,10 @@
}; };
WhalesongImmutableHashtable.prototype.functionalRemove = function(key) { WhalesongImmutableHashtable.prototype.functionalRemove = function(key) {
// this.hash.remove(key); return new WhalesongImmutableHashtable(this.type,
this.hash_function,
this.equality_function,
this.map.remove(key));
}; };
WhalesongImmutableHashtable.prototype.containsKey = function(key) { WhalesongImmutableHashtable.prototype.containsKey = function(key) {
@ -305,12 +344,6 @@
var isHash = function (x) { var isHash = function (x) {
return (x instanceof WhalesongHashtable || x instanceof WhalesongImmutableHashtable); return (x instanceof WhalesongHashtable || x instanceof WhalesongImmutableHashtable);
}; };
@ -325,8 +358,6 @@
// Arbitrary magic number. We have to cut off the hashing at some point. // Arbitrary magic number. We have to cut off the hashing at some point.
var MAX_HASH_DEPTH = 128; var MAX_HASH_DEPTH = 128;
@ -377,6 +408,8 @@
exports.getEqHashCode = getEqHashCode; exports.getEqHashCode = getEqHashCode;
exports.getEqualHashCode = getEqualHashCode; exports.getEqualHashCode = getEqualHashCode;
exports.getEqvHashCode = getEqvHashCode;
exports.hashMix = hashMix; exports.hashMix = hashMix;
exports.makeEqHashCode = makeEqHashCode; exports.makeEqHashCode = makeEqHashCode;
@ -386,9 +419,11 @@
exports.makeEqvHashtable = makeEqvHashtable; exports.makeEqvHashtable = makeEqvHashtable;
exports.makeEqualHashtable = makeEqualHashtable; exports.makeEqualHashtable = makeEqualHashtable;
exports.makeImmutableEqHashtable = makeImmutableEqHashtable;
exports.makeImmutableEqvHashtable = makeImmutableEqvHashtable;
exports.makeImmutableEqualHashtable = makeImmutableEqualHashtable;
exports.isHash = isHash; exports.isHash = isHash;
exports.isHashEqv = isHashEqv; exports.isHashEqv = isHashEqv;
exports.isHashEq = isHashEq; exports.isHashEq = isHashEq;
}(window.plt.baselib, Hashtable)); }(window.plt.baselib, Hashtable));

View File

@ -15,6 +15,7 @@
// show up outside this section! // show up outside this section!
var isNumber = baselib.numbers.isNumber; var isNumber = baselib.numbers.isNumber;
var isProcedure = baselib.functions.isProcedure;
var isReal = baselib.numbers.isReal; var isReal = baselib.numbers.isReal;
var isInexact = baselib.numbers.isInexact; var isInexact = baselib.numbers.isInexact;
var isComplex = baselib.numbers.isComplex; var isComplex = baselib.numbers.isComplex;
@ -118,6 +119,8 @@
var checkContinuationMarkSet = baselib.check.checkContinuationMarkSet; var checkContinuationMarkSet = baselib.check.checkContinuationMarkSet;
var checkExn = baselib.check.checkExn; var checkExn = baselib.check.checkExn;
var checkHash = baselib.check.checkHash; var checkHash = baselib.check.checkHash;
var checkMutableHash = baselib.check.checkMutableHash;
var checkImmutableHash = baselib.check.checkImmutableHash;
var checkAny = baselib.check.makeCheckArgumentType( var checkAny = baselib.check.makeCheckArgumentType(
function(x) { return true; }, function(x) { return true; },
'any'); 'any');
@ -127,12 +130,6 @@
// Primitives are the set of primitive values. Not all primitives // Primitives are the set of primitive values. Not all primitives
// are coded here; several of them (including call/cc) are injected by // are coded here; several of them (including call/cc) are injected by
// the bootstrapping code in compiler/boostrapped-primitives.rkt // the bootstrapping code in compiler/boostrapped-primitives.rkt
@ -1385,7 +1382,7 @@
'procedure?', 'procedure?',
1, 1,
function (M) { function (M) {
return baselib.functions.isProcedure(M.e[M.e.length - 1]); return isProcedure(M.e[M.e.length - 1]);
}); });
installPrimitiveProcedure( installPrimitiveProcedure(
@ -2504,6 +2501,15 @@
return hash; return hash;
}; };
var initializeImmutableHash = function(lst, hash) {
while (lst !== NULL) {
hash = hash.functionalPut(lst.first.first, lst.first.rest);
lst = lst.rest;
}
return hash;
};
installPrimitiveProcedure( installPrimitiveProcedure(
'hash?', 'hash?',
1, 1,
@ -2544,15 +2550,48 @@
return initializeHash(lst, plt.baselib.hashes.makeEqualHashtable()); return initializeHash(lst, plt.baselib.hashes.makeEqualHashtable());
}); });
installPrimitiveProcedure(
'make-immutable-hasheq',
makeList(0, 1),
function(M) {
var lst = NULL;
if (M.a === 1) {
lst = checkListofPairs(M, 'make-hasheq', 0);
}
return initializeImmutableHash(lst, plt.baselib.hashes.makeImmutableEqHashtable());
});
installPrimitiveProcedure(
'make-immutable-hasheqv',
makeList(0, 1),
function(M) {
var lst = NULL;
if (M.a === 1) {
lst = checkListofPairs(M, 'make-hasheqv', 0);
}
return initializeImmutableHash(lst, plt.baselib.hashes.makeImmutableEqvHashtable());
});
installPrimitiveProcedure(
'make-immutable-hash',
makeList(0, 1),
function(M) {
var lst = NULL;
if (M.a === 1) {
lst = checkListofPairs(M, 'make-hash', 0);
}
return initializeImmutableHash(lst, plt.baselib.hashes.makeImmutableEqualHashtable());
});
installPrimitiveClosure( installPrimitiveClosure(
'hash-ref', 'hash-ref',
makeList(2, 3), makeList(2, 3),
function(M) { function(M) {
var hash = checkHash(M, 'hash-ref', 0); var hash = checkHash(M, 'hash-ref', 0);
var key = checkAny(M, 'hash-ref', 1); var key = checkAny(M, 'hash-ref', 1);
var thunk; var thunkOrFailVal;
if (M.a === 3) { if (M.a === 3) {
thunk = checkProcedure(M, 'hash-ref', 2); thunkOrFailVal = checkAny(M, 'hash-ref', 2);
} }
if (hash.containsKey(key)) { if (hash.containsKey(key)) {
finalizeClosureCall(M, hash.get(key)); finalizeClosureCall(M, hash.get(key));
@ -2562,11 +2601,15 @@
M, M,
baselib.format.format("hash-ref: no value found for key: ~e", baselib.format.format("hash-ref: no value found for key: ~e",
[key])); [key]));
} else { } else {
M.p = thunk; if (isProcedure(thunkOrFailVal)) {
M.e.length -= M.a; M.p = thunkOrFailVal;
M.a = 0; M.e.length -= M.a;
baselib.functions.rawApply(M); M.a = 0;
baselib.functions.rawApply(M);
} else {
finalizeClosureCall(M, thunkOrFailVal);
}
} }
} }
}); });
@ -2575,13 +2618,23 @@
'hash-set!', 'hash-set!',
3, 3,
function(M){ function(M){
var hash = checkHash(M, 'hash-set!', 0); var hash = checkMutableHash(M, 'hash-set!', 0);
var key = checkAny(M, 'hash-set!', 1); var key = checkAny(M, 'hash-set!', 1);
var value = checkAny(M, 'hash-set!', 2); var value = checkAny(M, 'hash-set!', 2);
hash.put(key, value); hash.put(key, value);
return VOID; return VOID;
}); });
installPrimitiveProcedure(
'hash-set',
3,
function(M){
var hash = checkImmutableHash(M, 'hash-set', 0);
var key = checkAny(M, 'hash-set', 1);
var value = checkAny(M, 'hash-set', 2);
return hash.functionalPut(key, value);
});
installPrimitiveProcedure( installPrimitiveProcedure(
'hash-has-key?', 'hash-has-key?',
2, 2,

View File

@ -153,8 +153,12 @@
make-hash make-hash
make-hasheqv make-hasheqv
make-hasheq make-hasheq
make-immutable-hash
make-immutable-hasheqv
make-immutable-hasheq
hash-ref hash-ref
hash-set! hash-set!
hash-set
equal-hash-code equal-hash-code

View File

@ -21,3 +21,6 @@ not-found
1 1
1 1
1 1
danny
dyoo@hashcollision.org
unknown

View File

@ -61,4 +61,12 @@
(hash-ref ht "test") (hash-ref ht "test")
(hash-ref ht "that") (hash-ref ht "that")
(hash-ref ht "only") (hash-ref ht "only")
(hash-ref ht "test!") (hash-ref ht "test!")
(let* ([ht (make-immutable-hash)]
[ht (hash-set ht 'name "danny")]
[ht (hash-set ht 'email "dyoo@hashcollision.org")])
(displayln (hash-ref ht 'name "unknown"))
(displayln (hash-ref ht 'email "unknown"))
(displayln (hash-ref ht 'phone "unknown")))