special cases for small hashes in unsafe_scheme_hash_tree_iterate_*
The iterator saves the return points in a list. For small immutable hashes, encode the values in the list in the bits of a fixnum to avoid allocations.
This commit is contained in:
parent
7d90b27524
commit
5ef3a53002
|
@ -212,6 +212,27 @@
|
|||
(test-hash-iters-generic lst3 lst4)
|
||||
(test-hash-iters-specific lst3 lst4))
|
||||
|
||||
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Use keys that are a multile of a power of 2 to
|
||||
; get "almost" collisions that force the hash table
|
||||
; to use a deeper tree.
|
||||
|
||||
(let ()
|
||||
(define vals (for/list ([j (in-range 100)]) (add1 j)))
|
||||
(define sum-vals (for/sum ([v (in-list vals)]) v))
|
||||
(for ([shift (in-range 150)])
|
||||
(define keys (for/list ([j (in-range 100)])
|
||||
(arithmetic-shift j shift)))
|
||||
; test first the weak table to ensure the keys are not collected
|
||||
(define ht/weak (make-weak-hash (map cons keys vals)))
|
||||
(define sum-ht/weak (for/sum ([v (in-weak-hash-values ht/weak)]) v))
|
||||
(define ht/mut (make-hash (map cons keys vals)))
|
||||
(define sum-ht/mut (for/sum ([v (in-mutable-hash-values ht/mut)]) v))
|
||||
(define ht/immut (make-immutable-hash (map cons keys vals)))
|
||||
(define sum-ht/immut (for/sum ([v (in-immutable-hash-values ht/immut)]) v))
|
||||
(test #t = sum-vals sum-ht/weak sum-ht/mut sum-ht/immut)))
|
||||
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(let ()
|
||||
|
|
|
@ -2738,80 +2738,189 @@ Scheme_Object *scheme_hash_tree_next_pos(Scheme_Hash_Tree *tree, mzlonglong pos)
|
|||
# define HAMT_TRAVERSE_NEXT(i) ((i)+1)
|
||||
#endif
|
||||
|
||||
#define mzHAMT_MAX_INDEX_LEVEL 4 /* For the compressed form of the index */
|
||||
|
||||
/* instead of returning a pos, these unsafe iteration ops */
|
||||
/* return a view into the tree consisting of a: */
|
||||
/* - subtree */
|
||||
/* - subtree index */
|
||||
/* - stack of parent subtrees and indices */
|
||||
/* For small hashes, it uses a compressed representation as fixnums */
|
||||
/* - (#h i0) --> (+ (<< 1 5) i0) */
|
||||
/* - (#h i1 #h i0) --> (+ (<< 1 10) (<< i1 5) i0) */
|
||||
/* - (#h i2 #h i1 #h i0) --> (+ (<< 1 15) (<< i2 10) (<< i1 5) i0) */
|
||||
/* - ... */
|
||||
/* This speeds up performance of immutable hash table iteration. */
|
||||
/* These unsafe ops currently do not support REVERSE_HASH_TABLE_ORDER */
|
||||
/* to avoid unneeded popcount computations */
|
||||
Scheme_Object *scheme_unsafe_hash_tree_start(Scheme_Hash_Tree *ht)
|
||||
{
|
||||
Scheme_Object *stack = scheme_null;
|
||||
int i;
|
||||
Scheme_Object *stack;
|
||||
int j, i, i_n[mzHAMT_MAX_INDEX_LEVEL], level;
|
||||
Scheme_Hash_Tree *ht_n[mzHAMT_MAX_INDEX_LEVEL];
|
||||
|
||||
ht = resolve_placeholder(ht);
|
||||
|
||||
if (0 == ht->count)
|
||||
if (!ht->count)
|
||||
return scheme_false;
|
||||
|
||||
i = hamt_popcount(ht->bitmap)-1;
|
||||
|
||||
while (1) {
|
||||
if (HASHTR_SUBTREEP(ht->els[i])
|
||||
|| HASHTR_COLLISIONP(ht->els[i])) {
|
||||
stack = /* go down tree but save return point */
|
||||
scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
ht = (Scheme_Hash_Tree *)ht->els[i];
|
||||
i = hamt_popcount(ht->bitmap)-1;
|
||||
level = 0;
|
||||
|
||||
while ((HASHTR_SUBTREEP(ht->els[i])
|
||||
|| HASHTR_COLLISIONP(ht->els[i]))) {
|
||||
/* go down tree but save return point */
|
||||
if (level == -1) {
|
||||
stack = scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
} else if (level < mzHAMT_MAX_INDEX_LEVEL) {
|
||||
ht_n[level] = ht;
|
||||
i_n[level] = i;
|
||||
level++;
|
||||
} else {
|
||||
return scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
stack = scheme_null;
|
||||
for (j = 0; j < mzHAMT_MAX_INDEX_LEVEL; j++) {
|
||||
stack = scheme_make_pair((Scheme_Object *)ht_n[j],
|
||||
scheme_make_pair(scheme_make_integer(i_n[j]),
|
||||
stack));
|
||||
}
|
||||
stack = scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
level = -1;
|
||||
}
|
||||
ht = (Scheme_Hash_Tree *)ht->els[i];
|
||||
i = hamt_popcount(ht->bitmap)-1;
|
||||
}
|
||||
|
||||
if (level == -1) {
|
||||
stack = scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
return stack;
|
||||
} else {
|
||||
i = (1<<mzHAMT_LOG_WORD_SIZE) + i;
|
||||
for (j = level-1; j >= 0 ; j--) {
|
||||
i = (i<<mzHAMT_LOG_WORD_SIZE) + i_n[j];
|
||||
}
|
||||
return scheme_make_integer(i);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* args is a (cons subtree (cons subtree-index stack-of-parents)) */
|
||||
Scheme_Object *scheme_unsafe_hash_tree_next(Scheme_Object *args)
|
||||
/* args is a (cons subtree (cons subtree-index stack-of-parents))
|
||||
or the comppressed representation as a fixnum */
|
||||
XFORM_NONGCING void scheme_unsafe_hash_tree_subtree(Scheme_Object *obj, Scheme_Object *args,
|
||||
Scheme_Hash_Tree **_subtree, int *_i)
|
||||
{
|
||||
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
int i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
Scheme_Object *stack = SCHEME_CDDR(args);
|
||||
Scheme_Hash_Tree *subtree;
|
||||
int i;
|
||||
|
||||
if (SCHEME_PAIRP(args)) {
|
||||
subtree = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
} else {
|
||||
if (SCHEME_NP_CHAPERONEP(obj))
|
||||
subtree = (Scheme_Hash_Tree *)SCHEME_CHAPERONE_VAL(obj);
|
||||
else
|
||||
subtree = (Scheme_Hash_Tree *)obj;
|
||||
i = SCHEME_INT_VAL(args);
|
||||
while (i >= (1<<(2*mzHAMT_LOG_WORD_SIZE))) {
|
||||
subtree = (Scheme_Hash_Tree *)subtree->els[i & ((1<<mzHAMT_LOG_WORD_SIZE)-1)];
|
||||
i = i >> mzHAMT_LOG_WORD_SIZE;
|
||||
}
|
||||
i = i & ((1<<mzHAMT_LOG_WORD_SIZE)-1);
|
||||
}
|
||||
|
||||
*_subtree = subtree;
|
||||
*_i =i;
|
||||
}
|
||||
|
||||
/* args is a (cons subtree (cons subtree-index stack-of-parents))
|
||||
or the comppressed representation as a fixnum */
|
||||
Scheme_Object *scheme_unsafe_hash_tree_next(Scheme_Hash_Tree *ht, Scheme_Object *args)
|
||||
{
|
||||
Scheme_Object *stack;
|
||||
int j, i, i_n[mzHAMT_MAX_INDEX_LEVEL], level;
|
||||
Scheme_Hash_Tree *ht_n[mzHAMT_MAX_INDEX_LEVEL];
|
||||
|
||||
if (SCHEME_PAIRP(args)) {
|
||||
ht = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
stack = SCHEME_CDDR(args);
|
||||
level = -1; /* -1 = too big */
|
||||
} else {
|
||||
i = SCHEME_INT_VAL(args);
|
||||
level = 0;
|
||||
while (i >= (1<<(2*mzHAMT_LOG_WORD_SIZE))) {
|
||||
ht_n[level] = ht;
|
||||
i_n[level] = i & ((1<<mzHAMT_LOG_WORD_SIZE)-1);
|
||||
ht = (Scheme_Hash_Tree *)ht->els[i_n[level]];
|
||||
i = i >> mzHAMT_LOG_WORD_SIZE;
|
||||
level++;
|
||||
}
|
||||
i = i & ((1<<mzHAMT_LOG_WORD_SIZE)-1);
|
||||
}
|
||||
|
||||
/* ht = resolve_placeholder(ht); /\* only check this in iterate-first *\/ */
|
||||
|
||||
while(1) {
|
||||
while (1) {
|
||||
if (!i) { /* pop up the tree */
|
||||
if (SCHEME_NULLP(stack)) {
|
||||
return scheme_false;
|
||||
if (level == -1) {
|
||||
ht = (Scheme_Hash_Tree *)SCHEME_CAR(stack);
|
||||
i = SCHEME_INT_VAL(SCHEME_CADR(stack));
|
||||
stack = SCHEME_CDDR(stack);
|
||||
if (SCHEME_NULLP(stack))
|
||||
level = 0;
|
||||
} else if (!level) {
|
||||
return scheme_false;
|
||||
} else {
|
||||
ht = (Scheme_Hash_Tree *)SCHEME_CAR(stack);
|
||||
i = SCHEME_INT_VAL(SCHEME_CADR(stack));
|
||||
stack = SCHEME_CDDR(stack);
|
||||
level--;
|
||||
ht = ht_n[level];
|
||||
i = i_n[level];
|
||||
}
|
||||
} else {
|
||||
i -= 1;
|
||||
if (HASHTR_SUBTREEP(ht->els[i])
|
||||
|| HASHTR_COLLISIONP(ht->els[i])) {
|
||||
stack = /* go down tree but save return point */
|
||||
scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
ht = (Scheme_Hash_Tree *)ht->els[i];
|
||||
i = hamt_popcount(ht->bitmap);
|
||||
} else {
|
||||
return scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
} else { /* go to next node */
|
||||
i--;
|
||||
if (!(HASHTR_SUBTREEP(ht->els[i])
|
||||
|| HASHTR_COLLISIONP(ht->els[i]))) {
|
||||
if (level == -1) {
|
||||
stack = scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
return stack;
|
||||
} else {
|
||||
i = (1<<mzHAMT_LOG_WORD_SIZE) + i;
|
||||
for (j = level-1; j >= 0 ; j--) {
|
||||
i = (i<<mzHAMT_LOG_WORD_SIZE) + i_n[j];
|
||||
}
|
||||
return scheme_make_integer(i);
|
||||
}
|
||||
} else { /* go down tree but save return point */
|
||||
if (level == -1) {
|
||||
stack = scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
} else if (level < mzHAMT_MAX_INDEX_LEVEL) {
|
||||
ht_n[level] = ht;
|
||||
i_n[level] = i;
|
||||
level++;
|
||||
} else {
|
||||
stack = scheme_null;
|
||||
for (j = 0; j < mzHAMT_MAX_INDEX_LEVEL; j++) {
|
||||
stack = scheme_make_pair((Scheme_Object *)ht_n[j],
|
||||
scheme_make_pair(scheme_make_integer(i_n[j]),
|
||||
stack));
|
||||
}
|
||||
stack = scheme_make_pair((Scheme_Object *)ht,
|
||||
scheme_make_pair(scheme_make_integer(i),
|
||||
stack));
|
||||
level = -1;
|
||||
}
|
||||
ht = (Scheme_Hash_Tree *)ht->els[i];
|
||||
i = hamt_popcount(ht->bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XFORM_NONGCING static void hamt_at_index(Scheme_Hash_Tree *ht, mzlonglong pos,
|
||||
|
|
|
@ -4118,30 +4118,34 @@ Scheme_Object *unsafe_scheme_hash_tree_iterate_next(int argc, Scheme_Object *arg
|
|||
|
||||
if (SCHEME_NP_CHAPERONEP(o)) o = SCHEME_CHAPERONE_VAL(o);
|
||||
|
||||
return scheme_unsafe_hash_tree_next(argv[1]);
|
||||
return scheme_unsafe_hash_tree_next((Scheme_Hash_Tree *)o, argv[1]);
|
||||
}
|
||||
Scheme_Object *unsafe_scheme_hash_tree_iterate_key(int argc, Scheme_Object *argv[])
|
||||
{
|
||||
Scheme_Object *obj = argv[0], *args = argv[1], *key;
|
||||
Scheme_Hash_Tree *subtree = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
int i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
Scheme_Hash_Tree *subtree;
|
||||
int i;
|
||||
|
||||
scheme_unsafe_hash_tree_subtree(obj, args, &subtree, &i);
|
||||
key = subtree->els[i];
|
||||
|
||||
if (SCHEME_NP_CHAPERONEP(obj))
|
||||
return chaperone_hash_key("unsafe-weak-hash-iterate-key", obj, key);
|
||||
return chaperone_hash_key("unsafe-immutable-hash-iterate-key", obj, key);
|
||||
else
|
||||
return key;
|
||||
}
|
||||
Scheme_Object *unsafe_scheme_hash_tree_iterate_value(int argc, Scheme_Object *argv[])
|
||||
{
|
||||
Scheme_Object *obj = argv[0], *args = argv[1];
|
||||
Scheme_Hash_Tree *subtree = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
int i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
Scheme_Hash_Tree *subtree;
|
||||
int i;
|
||||
|
||||
scheme_unsafe_hash_tree_subtree(obj, args, &subtree, &i);
|
||||
|
||||
if (SCHEME_NP_CHAPERONEP(obj)) {
|
||||
Scheme_Object *chap_key, *chap_val;
|
||||
chaperone_hash_key_value("unsafe-weak-hash-iterate-value",
|
||||
obj, subtree->els[i], &chap_key, &chap_val, 0);
|
||||
chaperone_hash_key_value("unsafe-immutable-hash-iterate-value",
|
||||
obj, subtree->els[i], &chap_key, &chap_val, 0);
|
||||
return chap_val;
|
||||
} else {
|
||||
int popcount;
|
||||
|
@ -4151,15 +4155,17 @@ Scheme_Object *unsafe_scheme_hash_tree_iterate_value(int argc, Scheme_Object *ar
|
|||
}
|
||||
Scheme_Object *unsafe_scheme_hash_tree_iterate_pair(int argc, Scheme_Object *argv[])
|
||||
{
|
||||
Scheme_Object *obj = argv[0], *args = argv[1];
|
||||
Scheme_Hash_Tree *subtree = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
int i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
Scheme_Object *key = subtree->els[i];
|
||||
Scheme_Object *obj = argv[0], *args = argv[1], *key;
|
||||
Scheme_Hash_Tree *subtree;
|
||||
int i;
|
||||
|
||||
scheme_unsafe_hash_tree_subtree(obj, args, &subtree, &i);
|
||||
key = subtree->els[i];
|
||||
|
||||
if (SCHEME_NP_CHAPERONEP(obj)) {
|
||||
Scheme_Object *chap_key, *chap_val;
|
||||
chaperone_hash_key_value("unsafe-weak-hash-iterate-pair",
|
||||
obj, subtree->els[i], &chap_key, &chap_val, 0);
|
||||
chaperone_hash_key_value("unsafe-immutable-hash-iterate-pair",
|
||||
obj, subtree->els[i], &chap_key, &chap_val, 0);
|
||||
return scheme_make_pair(chap_key, chap_val);
|
||||
} else {
|
||||
Scheme_Object *val;
|
||||
|
@ -4171,14 +4177,16 @@ Scheme_Object *unsafe_scheme_hash_tree_iterate_pair(int argc, Scheme_Object *arg
|
|||
}
|
||||
Scheme_Object *unsafe_scheme_hash_tree_iterate_key_value(int argc, Scheme_Object *argv[])
|
||||
{
|
||||
Scheme_Object *obj = argv[0], *args = argv[1], *res[2];
|
||||
Scheme_Hash_Tree *subtree = (Scheme_Hash_Tree *)SCHEME_CAR(args);
|
||||
int i = SCHEME_INT_VAL(SCHEME_CADR(args));
|
||||
Scheme_Object *key = subtree->els[i];
|
||||
Scheme_Object *obj = argv[0], *args = argv[1], *key, *res[2];
|
||||
Scheme_Hash_Tree *subtree;
|
||||
int i;
|
||||
|
||||
scheme_unsafe_hash_tree_subtree(obj, args, &subtree, &i);
|
||||
key = subtree->els[i];
|
||||
|
||||
if (SCHEME_NP_CHAPERONEP(obj)) {
|
||||
chaperone_hash_key_value("unsafe-weak-hash-iterate-pair",
|
||||
obj, subtree->els[i], &res[0], &res[1], 0);
|
||||
chaperone_hash_key_value("unsafe-immutable-hash-iterate-pair",
|
||||
obj, subtree->els[i], &res[0], &res[1], 0);
|
||||
} else {
|
||||
Scheme_Object *val;
|
||||
int popcount;
|
||||
|
|
|
@ -966,7 +966,9 @@ Scheme_Object *scheme_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key);
|
|||
XFORM_NONGCING Scheme_Object *scheme_eq_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key);
|
||||
XFORM_NONGCING mzlonglong scheme_hash_tree_next(Scheme_Hash_Tree *tree, mzlonglong pos);
|
||||
Scheme_Object *scheme_unsafe_hash_tree_start(Scheme_Hash_Tree *ht);
|
||||
Scheme_Object *scheme_unsafe_hash_tree_next(Scheme_Object *args);
|
||||
XFORM_NONGCING void scheme_unsafe_hash_tree_subtree(Scheme_Object *obj, Scheme_Object *args,
|
||||
Scheme_Hash_Tree **_subtree, int *_i);
|
||||
Scheme_Object *scheme_unsafe_hash_tree_next(Scheme_Hash_Tree *ht, Scheme_Object *args);
|
||||
Scheme_Object *scheme_hash_tree_next_pos(Scheme_Hash_Tree *tree, mzlonglong pos);
|
||||
XFORM_NONGCING int scheme_hash_tree_index(Scheme_Hash_Tree *tree, mzlonglong pos, Scheme_Object **_key, Scheme_Object **_val);
|
||||
int scheme_hash_tree_equal(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2);
|
||||
|
|
Loading…
Reference in New Issue
Block a user