From 6de3659664be532bd195ca9b1abcb2b825824de2 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 26 Apr 2017 15:27:39 -0600 Subject: [PATCH] repair for `hash-keys-subset?` When comparing a part of a hamt that is a collision node versus a subtree node, a "hash code" was extracted from the collision node --- but that's really a code for an integer key is that used for the collision element. The comparison should instead use a code extracted from the reference to the collision node (which is the code that is common to all colliding keys). --- pkgs/racket-test-core/tests/racket/hash.rktl | 38 ++++++++++++++++++++ racket/src/racket/src/hamt_subset.inc | 5 +-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pkgs/racket-test-core/tests/racket/hash.rktl b/pkgs/racket-test-core/tests/racket/hash.rktl index d917d2b934..d9a3679545 100644 --- a/pkgs/racket-test-core/tests/racket/hash.rktl +++ b/pkgs/racket-test-core/tests/racket/hash.rktl @@ -35,6 +35,44 @@ #hash([one . 1] [two . 2] [three . 3] [four . 4])) h)) +(let () + (struct a (n m) + #:property + prop:equal+hash + (list (lambda (a b eql) (and (= (a-n a) (a-n b)) + (= (a-m a) (a-m b)))) + (lambda (a hc) (a-n a)) + (lambda (a hc) (a-n a)))) + + (define ht0 (hash (a 1 0) #t)) + ;; A hash table with two keys that have the same hash code + (define ht1 (hash (a 1 0) #t + (a 1 2) #t)) + ;; Another hash table with the same two keys, plus another + ;; with an extra key whose hash code is different but the + ;; same in the last 5 bits: + (define ht2 (hash (a 1 0) #t + (a 1 2) #t + (a 33 0) #t)) + ;; A hash table with no collision, but the same last + ;; 5 bits for both keys: + (define ht3 (hash (a 1 0) #t + (a 33 0) #t)) + + ;; Subset must compare a collision node with a subtree node (that + ;; contains a collision node): + (test #t hash-keys-subset? ht1 ht2) + + (test #t hash-keys-subset? ht3 ht2) + (test #t hash-keys-subset? ht0 ht3) + + (test #t hash-keys-subset? ht0 ht2) + (test #t hash-keys-subset? ht0 ht1) + (test #f hash-keys-subset? ht2 ht1) + (test #f hash-keys-subset? ht2 ht0) + (test #f hash-keys-subset? ht1 ht0) + (test #f hash-keys-subset? ht1 ht3)) + (let () (define-syntax (define-hash-iterations-tester stx) (syntax-case stx () diff --git a/racket/src/racket/src/hamt_subset.inc b/racket/src/racket/src/hamt_subset.inc index a72ddaa05f..e611ef22ef 100644 --- a/racket/src/racket/src/hamt_subset.inc +++ b/racket/src/racket/src/hamt_subset.inc @@ -89,9 +89,10 @@ HAMT_NONGCING int HAMT_SUBSET_OF(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2, int if (HASHTR_SUBTREEP(k2)) { /* check each element of collision */ + uintptr_t code; + code = _mzHAMT_CODE(t1, pos1, popcount1); for (i = ((Scheme_Hash_Tree *)k1)->count; i--; ) { - uintptr_t code; - hamt_at_index(((Scheme_Hash_Tree *)k1), i, &key, HAMT_IF_VAL(&val, NULL), &code); + hamt_at_index(((Scheme_Hash_Tree *)k1), i, &key, HAMT_IF_VAL(&val, NULL), NULL); if (!HAMT_ELEMENT_OF(key, HAMT_IF_VAL(val, NULL), code, (Scheme_Hash_Tree *)k2, shift + mzHAMT_LOG_WORD_SIZE,