fix hash proxying in the case that proxied key has no value

This commit is contained in:
Matthew Flatt 2010-09-10 12:38:37 -06:00
parent 2c9f8cebbd
commit ff9b535dc6
3 changed files with 107 additions and 13 deletions

View File

@ -291,6 +291,12 @@ other operations that use @scheme[hash-iterate-key] internally); it
must produce a replacement for the key, which is then reported as a must produce a replacement for the key, which is then reported as a
key extracted from the table. key extracted from the table.
The @racket[hash-iterate-value], @racket[hash-map], or
@racket[hash-for-each] functions use a combination of
@racket[hash-iterate-key] and @racket[hash-ref]. If a key
produced by @scheme[key-proc] does not yield a value through
@racket[hash-ref], then the @exnraise[exn:fail:contract].
Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments Pairs of @scheme[prop] and @scheme[prop-val] (the number of arguments
to @scheme[proxy-hash] must be odd) add proxy properties to @scheme[proxy-hash] must be odd) add proxy properties
or override proxy-property values of @scheme[hash].} or override proxy-property values of @scheme[hash].}

View File

@ -828,6 +828,50 @@
;; ---------------------------------------- ;; ----------------------------------------
;; Check broken key proxy:
(let ([check
(lambda (orig)
(let ([h (proxy-hash
orig
(λ (h k)
(values 'bad1
(λ (h k v)
'bad2)))
(λ (h k v) (values 'bad3 'bad4))
(λ (h k) 'bad5)
(λ (h k) 'bad6))])
(test (void) hash-set! h 1 2)
(test #f hash-ref h 1 #f)
(err/rt-test (hash-iterate-value h (hash-iterate-first h)))
(err/rt-test (hash-map h void))
(err/rt-test (hash-for-each h void))))])
(check (make-hash))
(check (make-hasheq))
(check (make-weak-hash))
(check (make-weak-hasheq)))
(let ([check
(lambda (orig)
(let ([h (chaperone-hash
orig
(λ (h k)
(values (chaperone-vector k (lambda (b i v) v) (lambda (b i v) v))
(λ (h k v) v)))
(λ (h k v) (values (chaperone-vector k (lambda (b i v) v) (lambda (b i v) v))
v))
(λ (h k) (chaperone-vector k (lambda (b i v) v) (lambda (b i v) v)))
(λ (h k) (chaperone-vector k (lambda (b i v) v) (lambda (b i v) v))))])
(let* ([vec (vector 1 2 3)]
[h (hash-set h vec 2)])
(test #f hash-ref h vec #f)
(err/rt-test (hash-iterate-value h (hash-iterate-first h)))
(err/rt-test (hash-map h void))
(err/rt-test (hash-for-each h void)))))])
(check (hasheq)))
;; ----------------------------------------
(let () (let ()
(define-struct a (x y) #:transparent) (define-struct a (x y) #:transparent)
(let* ([a1 (make-a 1 2)] (let* ([a1 (make-a 1 2)]

View File

@ -2021,6 +2021,7 @@ static Scheme_Object *hash_table_copy(int argc, Scheme_Object *argv[])
scheme_hash_tree_index(t, i, &k, &val); scheme_hash_tree_index(t, i, &k, &val);
if (!SAME_OBJ((Scheme_Object *)t, v)) if (!SAME_OBJ((Scheme_Object *)t, v))
val = scheme_chaperone_hash_traversal_get(v, k); val = scheme_chaperone_hash_traversal_get(v, k);
if (val)
scheme_hash_set(naya, k, val); scheme_hash_set(naya, k, val);
} }
@ -2330,6 +2331,11 @@ static Scheme_Object *do_map_hash_table(int argc,
v = chaperone_hash_key(name, chaperone, p[0]); v = chaperone_hash_key(name, chaperone, p[0]);
p[0] = v; p[0] = v;
v = scheme_chaperone_hash_get(chaperone, v); v = scheme_chaperone_hash_get(chaperone, v);
if (!v)
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"%s: no value found for post-proxy key: %V",
name,
p[0]);
} else } else
v = (Scheme_Object *)bucket->val; v = (Scheme_Object *)bucket->val;
if (v) { if (v) {
@ -2359,6 +2365,11 @@ static Scheme_Object *do_map_hash_table(int argc,
v = chaperone_hash_key(name, chaperone, p[0]); v = chaperone_hash_key(name, chaperone, p[0]);
p[0] = v; p[0] = v;
v = scheme_chaperone_hash_get(chaperone, v); v = scheme_chaperone_hash_get(chaperone, v);
if (!v)
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"%s: no value found for post-proxy key: %V",
name,
p[0]);
} else { } else {
v = hash->vals[i]; v = hash->vals[i];
} }
@ -2391,6 +2402,11 @@ static Scheme_Object *do_map_hash_table(int argc,
if (chaperone) { if (chaperone) {
ik = chaperone_hash_key(name, chaperone, ik); ik = chaperone_hash_key(name, chaperone, ik);
iv = scheme_chaperone_hash_get(chaperone, ik); iv = scheme_chaperone_hash_get(chaperone, ik);
if (!iv)
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"%s: no value found for post-chaperone key: %V",
name,
ik);
} }
if (iv) { if (iv) {
p[1] = iv; p[1] = iv;
@ -2524,7 +2540,7 @@ static Scheme_Object *hash_table_iterate_next(int argc, Scheme_Object *argv[])
static Scheme_Object *hash_table_index(const char *name, int argc, Scheme_Object *argv[], int get_val) static Scheme_Object *hash_table_index(const char *name, int argc, Scheme_Object *argv[], int get_val)
{ {
Scheme_Object *p = argv[1], *obj, *chaperone; Scheme_Object *p = argv[1], *obj, *chaperone, *key;
int pos, sz; int pos, sz;
obj = argv[0]; obj = argv[0];
@ -2551,9 +2567,15 @@ static Scheme_Object *hash_table_index(const char *name, int argc, Scheme_Object
if (pos < sz) { if (pos < sz) {
if (hash->vals[pos]) { if (hash->vals[pos]) {
if (chaperone) { if (chaperone) {
if (get_val) if (get_val) {
return scheme_chaperone_hash_get(chaperone, chaperone_hash_key(name, chaperone, hash->keys[pos])); key = chaperone_hash_key(name, chaperone, hash->keys[pos]);
else obj = scheme_chaperone_hash_get(chaperone, key);
if (!obj)
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"hash-iterate-value: no value found for post-proxy key: %V",
key);
return obj;
} else
return chaperone_hash_key(name, chaperone, hash->keys[pos]); return chaperone_hash_key(name, chaperone, hash->keys[pos]);
} else if (get_val) } else if (get_val)
return hash->vals[pos]; return hash->vals[pos];
@ -2565,9 +2587,15 @@ static Scheme_Object *hash_table_index(const char *name, int argc, Scheme_Object
Scheme_Object *v, *k; Scheme_Object *v, *k;
if (scheme_hash_tree_index((Scheme_Hash_Tree *)obj, pos, &k, &v)) { if (scheme_hash_tree_index((Scheme_Hash_Tree *)obj, pos, &k, &v)) {
if (chaperone) { if (chaperone) {
if (get_val) if (get_val) {
return scheme_chaperone_hash_get(chaperone, chaperone_hash_key(name, chaperone, k)); key = chaperone_hash_key(name, chaperone, k);
else obj = scheme_chaperone_hash_get(chaperone, key);
if (!obj)
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"hash-iterate-value: no value found for post-chaperone key: %V",
key);
return obj;
} else
return chaperone_hash_key(name, chaperone, k); return chaperone_hash_key(name, chaperone, k);
} else } else
return (get_val ? v : k); return (get_val ? v : k);
@ -2591,9 +2619,15 @@ static Scheme_Object *hash_table_index(const char *name, int argc, Scheme_Object
else else
obj = (Scheme_Object *)bucket->key; obj = (Scheme_Object *)bucket->key;
if (chaperone) { if (chaperone) {
if (get_val) if (get_val) {
return scheme_chaperone_hash_get(chaperone, chaperone_hash_key(name, chaperone, obj)); key = chaperone_hash_key(name, chaperone, obj);
else obj = scheme_chaperone_hash_get(chaperone, key);
if (!obj)
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
"hash-iterate-value: no value found for post-proxy key: %V",
key);
return obj;
} else
return chaperone_hash_key(name, chaperone, obj); return chaperone_hash_key(name, chaperone, obj);
} else } else
return obj; return obj;
@ -2709,7 +2743,12 @@ static Scheme_Object *chaperone_hash_op_k(void)
p->ku.k.p3 = NULL; p->ku.k.p3 = NULL;
p->ku.k.p4 = NULL; p->ku.k.p4 = NULL;
return chaperone_hash_op(who, o, k, v, p->ku.k.i1); o = chaperone_hash_op(who, o, k, v, p->ku.k.i1);
if (!o)
return scheme_false;
else
return scheme_box(o);
} }
static Scheme_Object *chaperone_hash_op_overflow(const char *who, Scheme_Object *o, Scheme_Object *k, static Scheme_Object *chaperone_hash_op_overflow(const char *who, Scheme_Object *o, Scheme_Object *k,
@ -2723,7 +2762,12 @@ static Scheme_Object *chaperone_hash_op_overflow(const char *who, Scheme_Object
p->ku.k.p4 = (void *)who; p->ku.k.p4 = (void *)who;
p->ku.k.i1 = mode; p->ku.k.i1 = mode;
return scheme_handle_stack_overflow(chaperone_hash_op_k); o = scheme_handle_stack_overflow(chaperone_hash_op_k);
if (SCHEME_FALSEP(o))
return NULL;
else
return SCHEME_BOX_VAL(o);
} }
static Scheme_Object *chaperone_hash_op(const char *who, Scheme_Object *o, Scheme_Object *k, static Scheme_Object *chaperone_hash_op(const char *who, Scheme_Object *o, Scheme_Object *k,