summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-10-23 06:54:36 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-10-23 06:54:36 -0700
commit27f65f30291b25afd2ea56618ecff49c69e7e85b (patch)
tree80d3b2a621a9ddffe9c865e998d6eb383c4cd34b
parentddd5c32143d0ed6a38cc0689e24246a53d6632aa (diff)
downloadtxr-27f65f30291b25afd2ea56618ecff49c69e7e85b.tar.gz
txr-27f65f30291b25afd2ea56618ecff49c69e7e85b.tar.bz2
txr-27f65f30291b25afd2ea56618ecff49c69e7e85b.zip
hash: optimization in remhash.
* hash.c (remhash): Walk chain to splice out to-be-removed entry using an approach similar to what is done in do_weak_tables to splice out lapsed weak entries. This eliminates one extra traversal of the chain as well as consing due to the ldiff call. We use raw pointers obtained using valptr, and direct assignment through *pchain because later cells in a chain are strictly older objects than earlier cells and so so the *pchain = cdr(*pchain) assignment cannot make a generation 1 object point to a generation 0 object.
-rw-r--r--hash.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/hash.c b/hash.c
index 444a32b8..7459ec8a 100644
--- a/hash.c
+++ b/hash.c
@@ -792,12 +792,16 @@ val remhash(val hash, val key)
struct hash *h = coerce(struct hash *, cobj_handle(hash, hash_s));
int lim = hash_rec_limit;
cnum hv = h->hash_fun(key, &lim);
- loc pchain = vecref_l(h->table, num_fast(hv % h->modulus));
- val existing = h->assoc_fun(key, hv, deref(pchain));
+ val *pchain = valptr(vecref_l(h->table, num_fast(hv % h->modulus)));
+ val existing = h->assoc_fun(key, hv, *pchain);
if (existing) {
- val cell = memq(existing, deref(pchain));
- set(pchain, nappend2(ldiff(deref(pchain), cell), cdr(cell)));
+ for (; *pchain; pchain = valptr(cdr_l(*pchain))) {
+ if (car(*pchain) == existing) {
+ *pchain = cdr(*pchain);
+ break;
+ }
+ }
h->count--;
bug_unless (h->count >= 0);
return cdr(existing);