improve complexity of `hash-iterate-{key,value}'
For immutable hashes, `hash-iterate-{key,value}' used to take O(N) time on the first call for a particular table and O(1) thereafter. Now it takes O(1) time for all calls, the constant is only slightly larger for the non-first calls, and there's no extra allocation.
This commit is contained in:
parent
773496642b
commit
7a8c2ff063
|
@ -1377,7 +1377,7 @@ static uintptr_t equal_hash_key(Scheme_Object *o, uintptr_t k, Hash_Info *hi)
|
||||||
hi->depth += 2;
|
hi->depth += 2;
|
||||||
old_depth = hi->depth;
|
old_depth = hi->depth;
|
||||||
|
|
||||||
for (i = ht->count; i--; ) {
|
for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
|
||||||
scheme_hash_tree_index(ht, i, &ik, &iv);
|
scheme_hash_tree_index(ht, i, &ik, &iv);
|
||||||
vk = equal_hash_key(ik, 0, hi);
|
vk = equal_hash_key(ik, 0, hi);
|
||||||
MZ_MIX(vk);
|
MZ_MIX(vk);
|
||||||
|
@ -1833,7 +1833,7 @@ static uintptr_t equal_hash_key2(Scheme_Object *o, Hash_Info *hi)
|
||||||
hi->depth += 2;
|
hi->depth += 2;
|
||||||
old_depth = hi->depth;
|
old_depth = hi->depth;
|
||||||
|
|
||||||
for (i = ht->count; i--; ) {
|
for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
|
||||||
scheme_hash_tree_index(ht, i, &ik, &iv);
|
scheme_hash_tree_index(ht, i, &ik, &iv);
|
||||||
k += equal_hash_key2(ik, hi);
|
k += equal_hash_key2(ik, hi);
|
||||||
k += equal_hash_key2(iv, hi);
|
k += equal_hash_key2(iv, hi);
|
||||||
|
@ -1915,7 +1915,7 @@ typedef struct AVLNode {
|
||||||
MZTAG_IF_REQUIRED
|
MZTAG_IF_REQUIRED
|
||||||
char height;
|
char height;
|
||||||
uintptr_t code;
|
uintptr_t code;
|
||||||
Scheme_Object *key; /* NULL => val is list of key-value pairs */
|
Scheme_Object *key; /* NULL => val is another tree for multiple key-value pairs */
|
||||||
Scheme_Object *val;
|
Scheme_Object *val;
|
||||||
struct AVLNode *left;
|
struct AVLNode *left;
|
||||||
struct AVLNode *right;
|
struct AVLNode *right;
|
||||||
|
@ -2176,113 +2176,141 @@ Scheme_Hash_Tree *scheme_make_hash_tree(int kind)
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Hash_Tree *scheme_hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *key, Scheme_Object *val)
|
static intptr_t search_nodes(AVLNode *n, Scheme_Object *key, int kind)
|
||||||
|
/* O(N) search full tree to find a code for `key'; returns -1 if not found */
|
||||||
|
{
|
||||||
|
intptr_t code;
|
||||||
|
|
||||||
|
if ((kind && ((kind == 1)
|
||||||
|
? scheme_equal(n->key, key)
|
||||||
|
: scheme_eqv(n->key, key)))
|
||||||
|
|| (!kind && SAME_OBJ(n->key, key)))
|
||||||
|
return n->code;
|
||||||
|
|
||||||
|
if (n->left) {
|
||||||
|
code = search_nodes(n->left, key, kind);
|
||||||
|
if (code >= 0)
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n->right)
|
||||||
|
return search_nodes(n->right, key, kind);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFORM_NONGCING static intptr_t search_nodes_eq(AVLNode *n, Scheme_Object *key)
|
||||||
|
/* O(N) search full tree to find a code for `key'; returns -1 if not found */
|
||||||
|
{
|
||||||
|
intptr_t code;
|
||||||
|
|
||||||
|
if (SAME_OBJ(n->key, key))
|
||||||
|
return n->code;
|
||||||
|
|
||||||
|
if (n->left) {
|
||||||
|
code = search_nodes_eq(n->left, key);
|
||||||
|
if (code >= 0)
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n->right)
|
||||||
|
return search_nodes_eq(n->right, key);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFORM_NONGCING static intptr_t fresh_code(AVLNode *root)
|
||||||
|
/* O(n) search for an available code */
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (1) {
|
||||||
|
if (!avl_find(i, root))
|
||||||
|
return i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *key, Scheme_Object *val, intptr_t h,
|
||||||
|
AVLNode *root, int kind)
|
||||||
{
|
{
|
||||||
Scheme_Hash_Tree *tree2;
|
Scheme_Hash_Tree *tree2;
|
||||||
uintptr_t h;
|
AVLNode *added;
|
||||||
AVLNode *root, *added;
|
|
||||||
int delta;
|
int delta;
|
||||||
|
|
||||||
if (SCHEME_HASHTR_FLAGS(tree) & 0x3) {
|
|
||||||
if (SCHEME_HASHTR_FLAGS(tree) & 0x1) {
|
|
||||||
h = to_unsigned_hash(scheme_equal_hash_key(key));
|
|
||||||
} else {
|
|
||||||
h = to_unsigned_hash(scheme_eqv_hash_key(key));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
h = PTR_TO_LONG((Scheme_Object *)key);
|
|
||||||
h = h >> 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!val) {
|
if (!val) {
|
||||||
/* Removing ... */
|
/* Removing ... */
|
||||||
added = avl_find(h, tree->root);
|
added = avl_find(h, root);
|
||||||
if (!added)
|
if (!added) {
|
||||||
return tree; /* nothing to remove */
|
/* nothing to remove */
|
||||||
|
return (tree ? (void *)tree : (void *)root);
|
||||||
|
}
|
||||||
if (added->key) {
|
if (added->key) {
|
||||||
int kind = (SCHEME_HASHTR_FLAGS(tree) & 0x3);
|
|
||||||
|
|
||||||
if ((kind && ((kind == 1)
|
if ((kind && ((kind == 1)
|
||||||
? scheme_equal(added->key, key)
|
? scheme_equal(added->key, key)
|
||||||
: scheme_eqv(added->key, key)))
|
: scheme_eqv(added->key, key)))
|
||||||
|| (!kind && SAME_OBJ(added->key, key))) {
|
|| (!kind && SAME_OBJ(added->key, key))) {
|
||||||
/* remove single item */
|
/* remove single item */
|
||||||
root = avl_del(tree->root, h);
|
root = avl_del(root, h);
|
||||||
|
|
||||||
tree2 = MALLOC_ONE_TAGGED(Scheme_Hash_Tree);
|
if (tree) {
|
||||||
memcpy(tree2, tree, sizeof(Scheme_Hash_Tree));
|
tree2 = MALLOC_ONE_TAGGED(Scheme_Hash_Tree);
|
||||||
tree2->elems_box = NULL;
|
memcpy(tree2, tree, sizeof(Scheme_Hash_Tree));
|
||||||
|
|
||||||
tree2->root = root;
|
tree2->root = root;
|
||||||
--tree2->count;
|
--tree2->count;
|
||||||
|
|
||||||
return tree2;
|
return tree2;
|
||||||
|
} else
|
||||||
|
return root;
|
||||||
} else {
|
} else {
|
||||||
/* Nothing to remove */
|
/* Nothing to remove */
|
||||||
return tree;
|
return (tree ? (void *)tree : (void *)root);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* multiple mappings; remove it below */
|
/* multiple mappings; remove it below */
|
||||||
root = tree->root;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Adding/setting: */
|
/* Adding/setting: */
|
||||||
root = avl_ins(h, NULL, NULL, tree->root);
|
root = avl_ins(h, NULL, NULL, root);
|
||||||
added = avl_find(h, root);
|
added = avl_find(h, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = 0;
|
delta = 0;
|
||||||
|
|
||||||
if (added->val) {
|
if (added->val) {
|
||||||
int kind = (SCHEME_HASHTR_FLAGS(tree) & 0x3);
|
|
||||||
|
|
||||||
if (!added->key) {
|
if (!added->key) {
|
||||||
/* Have a list of keys and vals. In this case, val can be NULL
|
/* Have a subtree of keys and vals (with bogus "code"s). */
|
||||||
to implement removal. */
|
AVLNode *savl = (AVLNode *)added->val;
|
||||||
Scheme_Object *prs = added->val, *a;
|
intptr_t code;
|
||||||
int cnt = 0;
|
code = search_nodes(savl, key, kind);
|
||||||
while (prs) {
|
if (code < 0) {
|
||||||
a = SCHEME_CAR(prs);
|
|
||||||
if (kind) {
|
|
||||||
if (kind == 1) {
|
|
||||||
if (scheme_equal(SCHEME_CAR(a), key))
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (scheme_eqv(SCHEME_CAR(a), key))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SAME_OBJ(SCHEME_CAR(a), key))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prs = SCHEME_CDR(prs);
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
if (!prs) {
|
|
||||||
/* Not mapped already: */
|
/* Not mapped already: */
|
||||||
if (!val) return tree; /* nothing to remove after all */
|
if (!val) {
|
||||||
val = scheme_make_raw_pair(scheme_make_raw_pair(key, val), added->val);
|
/* nothing to remove after all */
|
||||||
|
return (tree ? (void *)tree : (void *)root);
|
||||||
|
}
|
||||||
|
savl = (AVLNode *)hash_tree_set(NULL, key, val, fresh_code(savl), savl, kind);
|
||||||
|
val = (Scheme_Object *)savl;
|
||||||
key = NULL;
|
key = NULL;
|
||||||
delta = 1;
|
delta = 1;
|
||||||
} else {
|
} else {
|
||||||
/* Mapped already: */
|
/* Mapped already: */
|
||||||
prs = SCHEME_CDR(prs);
|
savl = (AVLNode *)hash_tree_set(NULL, key, val, code, savl, kind);
|
||||||
for (a = added->val; cnt--; a = SCHEME_CDR(a)) {
|
|
||||||
prs = scheme_make_raw_pair(SCHEME_CAR(a), prs);
|
|
||||||
}
|
|
||||||
if (val) {
|
if (val) {
|
||||||
prs = scheme_make_raw_pair(scheme_make_raw_pair(key, val),
|
/* Updated */
|
||||||
prs);
|
val = (Scheme_Object *)savl;
|
||||||
|
key = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
/* Removed */
|
||||||
delta = -1;
|
delta = -1;
|
||||||
}
|
if (!savl->left && !savl->right) {
|
||||||
val = prs;
|
/* Removal reduced to a single mapping: */
|
||||||
key = NULL;
|
val = savl->val;
|
||||||
if (!SCHEME_CDR(prs)) {
|
key = savl->key;
|
||||||
/* Removal reduced to a single mapping: */
|
} else {
|
||||||
a = SCHEME_CAR(prs);
|
val = (Scheme_Object *)savl;
|
||||||
key = SCHEME_CAR(a);
|
key = NULL;
|
||||||
val = SCHEME_CDR(a);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2297,9 +2325,15 @@ Scheme_Hash_Tree *scheme_hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *ke
|
||||||
same = SAME_OBJ(key, added->key);
|
same = SAME_OBJ(key, added->key);
|
||||||
}
|
}
|
||||||
if (!same) {
|
if (!same) {
|
||||||
val = scheme_make_raw_pair(scheme_make_raw_pair(key, val),
|
/* Switch to sub-tree mode to hold mulitple keys for the
|
||||||
scheme_make_raw_pair(scheme_make_raw_pair(added->key, added->val),
|
same code: */
|
||||||
NULL));
|
static AVLNode *sn;
|
||||||
|
|
||||||
|
/* avoid intermediate allocations by constructing directly: */
|
||||||
|
sn = make_avl(NULL, 1, added->key, added->val, NULL);
|
||||||
|
sn = make_avl(NULL, 0, key, val, sn);
|
||||||
|
|
||||||
|
val = (Scheme_Object *)sn;
|
||||||
key = NULL;
|
key = NULL;
|
||||||
delta = 1;
|
delta = 1;
|
||||||
}
|
}
|
||||||
|
@ -2315,15 +2349,36 @@ Scheme_Hash_Tree *scheme_hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *ke
|
||||||
delta = 1;
|
delta = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree2 = MALLOC_ONE_TAGGED(Scheme_Hash_Tree);
|
if (tree) {
|
||||||
memcpy(tree2, tree, sizeof(Scheme_Hash_Tree));
|
tree2 = MALLOC_ONE_TAGGED(Scheme_Hash_Tree);
|
||||||
tree2->elems_box = NULL;
|
memcpy(tree2, tree, sizeof(Scheme_Hash_Tree));
|
||||||
|
|
||||||
if (delta)
|
if (delta)
|
||||||
tree2->count += delta;
|
tree2->count += delta;
|
||||||
tree2->root = root;
|
tree2->root = root;
|
||||||
|
|
||||||
return tree2;
|
return tree2;
|
||||||
|
} else
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scheme_Hash_Tree *scheme_hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *key, Scheme_Object *val)
|
||||||
|
{
|
||||||
|
uintptr_t h;
|
||||||
|
int kind = (SCHEME_HASHTR_FLAGS(tree) & 0x3);
|
||||||
|
|
||||||
|
if (kind) {
|
||||||
|
if (kind == 1) {
|
||||||
|
h = to_unsigned_hash(scheme_equal_hash_key(key));
|
||||||
|
} else {
|
||||||
|
h = to_unsigned_hash(scheme_eqv_hash_key(key));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h = PTR_TO_LONG((Scheme_Object *)key);
|
||||||
|
h = h >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Scheme_Hash_Tree *)hash_tree_set(tree, key, val, h, tree->root, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scheme_Object *scheme_eq_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key)
|
Scheme_Object *scheme_eq_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key)
|
||||||
|
@ -2337,13 +2392,13 @@ Scheme_Object *scheme_eq_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *ke
|
||||||
avl = avl_find(h, tree->root);
|
avl = avl_find(h, tree->root);
|
||||||
if (avl) {
|
if (avl) {
|
||||||
if (!avl->key) {
|
if (!avl->key) {
|
||||||
/* Have list of keys & vals: */
|
/* Have tree */
|
||||||
Scheme_Object *prs = avl->val, *a;
|
AVLNode *savl = (AVLNode *)avl->val;
|
||||||
while (prs) {
|
intptr_t code;
|
||||||
a = SCHEME_CAR(prs);
|
code = search_nodes_eq(savl, key);
|
||||||
if (SAME_OBJ(SCHEME_CAR(a), key))
|
if (code >= 0) {
|
||||||
return SCHEME_CDR(a);
|
avl = avl_find(code, savl);
|
||||||
prs = SCHEME_CDR(prs);
|
return avl->val;
|
||||||
}
|
}
|
||||||
} else if (SAME_OBJ(avl->key, key))
|
} else if (SAME_OBJ(avl->key, key))
|
||||||
return avl->val;
|
return avl->val;
|
||||||
|
@ -2370,18 +2425,13 @@ Scheme_Object *scheme_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key)
|
||||||
avl = avl_find(h, tree->root);
|
avl = avl_find(h, tree->root);
|
||||||
if (avl) {
|
if (avl) {
|
||||||
if (!avl->key) {
|
if (!avl->key) {
|
||||||
/* Have list of keys & vals: */
|
/* Have tree */
|
||||||
Scheme_Object *prs = avl->val, *a;
|
AVLNode *savl = (AVLNode *)avl->val;
|
||||||
while (prs) {
|
intptr_t code;
|
||||||
a = SCHEME_CAR(prs);
|
code = search_nodes(savl, key, kind);
|
||||||
if (kind == 1) {
|
if (code >= 0) {
|
||||||
if (scheme_equal(SCHEME_CAR(a), key))
|
avl = avl_find(code, savl);
|
||||||
return SCHEME_CDR(a);
|
return avl->val;
|
||||||
} else {
|
|
||||||
if (scheme_eqv(SCHEME_CAR(a), key))
|
|
||||||
return SCHEME_CDR(a);
|
|
||||||
}
|
|
||||||
prs = SCHEME_CDR(prs);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (kind == 1) {
|
if (kind == 1) {
|
||||||
|
@ -2397,71 +2447,95 @@ Scheme_Object *scheme_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t scheme_hash_tree_next(Scheme_Hash_Tree *tree, intptr_t pos)
|
XFORM_NONGCING intptr_t path_next(AVLNode *avl, intptr_t path)
|
||||||
{
|
|
||||||
if (pos >= tree->count)
|
|
||||||
return -2;
|
|
||||||
pos++;
|
|
||||||
if (tree->count > pos)
|
|
||||||
return pos;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fill_elems(AVLNode *avl, Scheme_Object *vec, intptr_t pos, intptr_t count)
|
|
||||||
{
|
{
|
||||||
if (!avl)
|
if (!avl)
|
||||||
return pos;
|
return -1;
|
||||||
|
|
||||||
if (avl->left)
|
if (!avl->key) {
|
||||||
pos = fill_elems(avl->left, vec, pos, count);
|
/* subtree choice */
|
||||||
|
if (path & 0x1) {
|
||||||
if (avl->key) {
|
/* in subtree or right */
|
||||||
SCHEME_VEC_ELS(vec)[pos] = avl->val;
|
if (!(path & 0x2)) {
|
||||||
SCHEME_VEC_ELS(vec)[pos + count] = avl->key;
|
/* haven't exhausted the subtree, yet: */
|
||||||
pos++;
|
path >>= 2;
|
||||||
} else {
|
path = path_next((AVLNode *)avl->val, path);
|
||||||
Scheme_Object *prs = avl->val, *a;
|
if (path > 0)
|
||||||
while (prs) {
|
return (path << 2) | 0x1;
|
||||||
a = SCHEME_CAR(prs);
|
path = 0x1; /* move on to right */
|
||||||
SCHEME_VEC_ELS(vec)[pos] = SCHEME_CDR(a);
|
} else {
|
||||||
SCHEME_VEC_ELS(vec)[pos + count] = SCHEME_CAR(a);
|
/* we have exhausted the subtree, and we're working on right */
|
||||||
pos++;
|
path >>= 1;
|
||||||
prs = SCHEME_CDR(prs);
|
/* assert: path & 0x1 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avl->right)
|
if (path & 0x1) {
|
||||||
pos = fill_elems(avl->right, vec, pos, count);
|
path = path_next(avl->right, path >> 1);
|
||||||
|
/* The result cannot be 0.
|
||||||
|
If the result is -1, then the following calculation preserves the -1.
|
||||||
|
If the result is positive, then we preserve the decision to go right here. */
|
||||||
|
if (avl->key)
|
||||||
|
return (path << 1) | 0x1;
|
||||||
|
else
|
||||||
|
return (path << 2) | 0x3;
|
||||||
|
}
|
||||||
|
|
||||||
return pos;
|
path = path_next(avl->left, path >> 1);
|
||||||
|
if (path > 0)
|
||||||
|
return path << 1;
|
||||||
|
|
||||||
|
/* start here */
|
||||||
|
if (avl->key)
|
||||||
|
return 0x1;
|
||||||
|
else {
|
||||||
|
/* start subtree */
|
||||||
|
path = path_next((AVLNode *)avl->val, 0);
|
||||||
|
return (path << 2) | 0x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFORM_NONGCING int path_find(AVLNode *avl, intptr_t path, Scheme_Object **_key, Scheme_Object **_val)
|
||||||
|
{
|
||||||
|
if (!avl) return 0;
|
||||||
|
|
||||||
|
if (!avl->key) {
|
||||||
|
/* subtree choice */
|
||||||
|
if (path & 0x1) {
|
||||||
|
/* in subtree or right */
|
||||||
|
if (!(path & 0x2)) {
|
||||||
|
/* in subtree */
|
||||||
|
return path_find((AVLNode *)avl->val, path >> 2, _key, _val);
|
||||||
|
} else {
|
||||||
|
/* in right */
|
||||||
|
path >>= 1;
|
||||||
|
/* assert: path & 0x1 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path & 0x1) {
|
||||||
|
if (path >> 1)
|
||||||
|
return path_find(avl->right, path >> 1, _key, _val);
|
||||||
|
else {
|
||||||
|
*_key = avl->key;
|
||||||
|
*_val = avl->val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return path_find(avl->left, path >> 1, _key, _val);
|
||||||
|
}
|
||||||
|
|
||||||
|
intptr_t scheme_hash_tree_next(Scheme_Hash_Tree *tree, intptr_t pos)
|
||||||
|
{
|
||||||
|
/* Iteration uses a key where the bits say when to turn right */
|
||||||
|
return path_next(tree->root, ((pos == -1) ? 0 : pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
int scheme_hash_tree_index(Scheme_Hash_Tree *tree, intptr_t pos, Scheme_Object **_key, Scheme_Object **_val)
|
int scheme_hash_tree_index(Scheme_Hash_Tree *tree, intptr_t pos, Scheme_Object **_key, Scheme_Object **_val)
|
||||||
{
|
{
|
||||||
Scheme_Object *elems, *elems_box;
|
return path_find(tree->root, pos, _key, _val);
|
||||||
|
|
||||||
if ((pos < 0) || (pos >= tree->count))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
elems_box = tree->elems_box;
|
|
||||||
if (elems_box)
|
|
||||||
elems = SCHEME_WEAK_BOX_VAL(elems_box);
|
|
||||||
else
|
|
||||||
elems = NULL;
|
|
||||||
if (!elems) {
|
|
||||||
AVL_ASSERT_ONLY(int total_pos);
|
|
||||||
elems = scheme_make_vector(tree->count * 2, NULL);
|
|
||||||
AVL_ASSERT_ONLY(total_pos = ) fill_elems(tree->root, elems, 0, tree->count);
|
|
||||||
AVL_ASSERT(total_pos == tree->count);
|
|
||||||
elems_box = scheme_make_weak_box(elems);
|
|
||||||
tree->elems_box = elems_box;
|
|
||||||
}
|
|
||||||
|
|
||||||
*_val = SCHEME_VEC_ELS(elems)[pos];
|
|
||||||
*_key = SCHEME_VEC_ELS(elems)[tree->count + pos];
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int scheme_hash_tree_equal_rec(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2, void *eql)
|
int scheme_hash_tree_equal_rec(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2, void *eql)
|
||||||
|
@ -2473,7 +2547,7 @@ int scheme_hash_tree_equal_rec(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2, void
|
||||||
|| ((SCHEME_HASHTR_FLAGS(t1) & 0x3) != (SCHEME_HASHTR_FLAGS(t2) & 0x3)))
|
|| ((SCHEME_HASHTR_FLAGS(t1) & 0x3) != (SCHEME_HASHTR_FLAGS(t2) & 0x3)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = t1->count; i--; ) {
|
for (i = scheme_hash_tree_next(t1, -1); i != -1; i = scheme_hash_tree_next(t1, i)) {
|
||||||
scheme_hash_tree_index(t1, i, &k, &v);
|
scheme_hash_tree_index(t1, i, &k, &v);
|
||||||
v2 = scheme_hash_tree_get(t2, k);
|
v2 = scheme_hash_tree_get(t2, k);
|
||||||
if (!v2)
|
if (!v2)
|
||||||
|
|
|
@ -2160,7 +2160,7 @@ static Scheme_Object *hash_table_copy(int argc, Scheme_Object *argv[])
|
||||||
else
|
else
|
||||||
naya = scheme_make_hash_table(SCHEME_hash_ptr);
|
naya = scheme_make_hash_table(SCHEME_hash_ptr);
|
||||||
|
|
||||||
for (i = t->count; i--; ) {
|
for (i = scheme_hash_tree_next(t, -1); i != -1; i = scheme_hash_tree_next(t, i)) {
|
||||||
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, &k);
|
val = scheme_chaperone_hash_traversal_get(v, k, &k);
|
||||||
|
|
|
@ -4580,7 +4580,7 @@ void scheme_check_unsafe_accessible(Scheme_Object *insp, Scheme_Env *from_env)
|
||||||
int i;
|
int i;
|
||||||
Scheme_Object *k, *v;
|
Scheme_Object *k, *v;
|
||||||
|
|
||||||
for (i = t->count; i--; ) {
|
for (i = scheme_hash_tree_next(t, -1); i != -1; i = scheme_hash_tree_next(t, i)) {
|
||||||
scheme_hash_tree_index(t, i, &k, &v);
|
scheme_hash_tree_index(t, i, &k, &v);
|
||||||
insp = k;
|
insp = k;
|
||||||
if (scheme_module_protected_wrt(unsafe_env->guard_insp, insp)) {
|
if (scheme_module_protected_wrt(unsafe_env->guard_insp, insp)) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ static int hash_tree_val_MARK(void *p, struct NewGC *gc) {
|
||||||
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)p;
|
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)p;
|
||||||
|
|
||||||
gcMARK2(ht->root, gc);
|
gcMARK2(ht->root, gc);
|
||||||
gcMARK2(ht->elems_box, gc);
|
|
||||||
|
|
||||||
return
|
return
|
||||||
gcBYTES_TO_WORDS(sizeof(Scheme_Hash_Tree));
|
gcBYTES_TO_WORDS(sizeof(Scheme_Hash_Tree));
|
||||||
|
@ -19,7 +18,6 @@ static int hash_tree_val_FIXUP(void *p, struct NewGC *gc) {
|
||||||
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)p;
|
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)p;
|
||||||
|
|
||||||
gcFIXUP2(ht->root, gc);
|
gcFIXUP2(ht->root, gc);
|
||||||
gcFIXUP2(ht->elems_box, gc);
|
|
||||||
|
|
||||||
return
|
return
|
||||||
gcBYTES_TO_WORDS(sizeof(Scheme_Hash_Tree));
|
gcBYTES_TO_WORDS(sizeof(Scheme_Hash_Tree));
|
||||||
|
|
|
@ -1483,7 +1483,6 @@ hash_tree_val {
|
||||||
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)p;
|
Scheme_Hash_Tree *ht = (Scheme_Hash_Tree *)p;
|
||||||
|
|
||||||
gcMARK2(ht->root, gc);
|
gcMARK2(ht->root, gc);
|
||||||
gcMARK2(ht->elems_box, gc);
|
|
||||||
|
|
||||||
size:
|
size:
|
||||||
gcBYTES_TO_WORDS(sizeof(Scheme_Hash_Tree));
|
gcBYTES_TO_WORDS(sizeof(Scheme_Hash_Tree));
|
||||||
|
|
|
@ -2301,7 +2301,7 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
|
||||||
Scheme_Hash_Table *t;
|
Scheme_Hash_Table *t;
|
||||||
Scheme_Hash_Tree *tr;
|
Scheme_Hash_Tree *tr;
|
||||||
Scheme_Object **keys, **vals, *val, *key, *orig;
|
Scheme_Object **keys, **vals, *val, *key, *orig;
|
||||||
int i, size, did_one = 0;
|
int i, size, did_one = 0, pos;
|
||||||
|
|
||||||
orig = obj;
|
orig = obj;
|
||||||
if (SCHEME_NP_CHAPERONEP(obj))
|
if (SCHEME_NP_CHAPERONEP(obj))
|
||||||
|
@ -2362,10 +2362,12 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
|
||||||
vals = NULL;
|
vals = NULL;
|
||||||
size = tr->count;
|
size = tr->count;
|
||||||
}
|
}
|
||||||
|
pos = -1;
|
||||||
for (i = 0; i < size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
if (!vals || vals[i]) {
|
if (!vals || vals[i]) {
|
||||||
if (!vals) {
|
if (!vals) {
|
||||||
scheme_hash_tree_index(tr, i, &key, &val);
|
pos = scheme_hash_tree_next(tr, pos);
|
||||||
|
scheme_hash_tree_index(tr, pos, &key, &val);
|
||||||
if (!SAME_OBJ(obj, orig))
|
if (!SAME_OBJ(obj, orig))
|
||||||
val = scheme_chaperone_hash_traversal_get(orig, key, &key);
|
val = scheme_chaperone_hash_traversal_get(orig, key, &key);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2182,7 +2182,7 @@ static Scheme_Object *resolve_references(Scheme_Object *obj,
|
||||||
kind = 0;
|
kind = 0;
|
||||||
t = (Scheme_Hash_Tree *)obj;
|
t = (Scheme_Hash_Tree *)obj;
|
||||||
lst = scheme_null;
|
lst = scheme_null;
|
||||||
for (i = t->count; i--; ) {
|
for (i = scheme_hash_tree_next(t, -1); i != -1; i = scheme_hash_tree_next(t, i)) {
|
||||||
scheme_hash_tree_index(t, i, &key, &val);
|
scheme_hash_tree_index(t, i, &key, &val);
|
||||||
lst = scheme_make_pair(scheme_make_pair(key, val), lst);
|
lst = scheme_make_pair(scheme_make_pair(key, val), lst);
|
||||||
}
|
}
|
||||||
|
@ -2210,7 +2210,6 @@ static Scheme_Object *resolve_references(Scheme_Object *obj,
|
||||||
|
|
||||||
t->count = base->count;
|
t->count = base->count;
|
||||||
t->root = base->root;
|
t->root = base->root;
|
||||||
t->elems_box = base->elems_box;
|
|
||||||
} else if (SCHEME_HASHTP(obj)) {
|
} else if (SCHEME_HASHTP(obj)) {
|
||||||
int i;
|
int i;
|
||||||
Scheme_Object *key, *val, *l = scheme_null, *orig_l;
|
Scheme_Object *key, *val, *l = scheme_null, *orig_l;
|
||||||
|
|
|
@ -507,8 +507,8 @@ MZ_EXTERN Scheme_Hash_Tree *scheme_make_hash_tree(int kind);
|
||||||
MZ_EXTERN Scheme_Hash_Tree *scheme_hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *key, Scheme_Object *val);
|
MZ_EXTERN Scheme_Hash_Tree *scheme_hash_tree_set(Scheme_Hash_Tree *tree, Scheme_Object *key, Scheme_Object *val);
|
||||||
MZ_EXTERN Scheme_Object *scheme_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key);
|
MZ_EXTERN Scheme_Object *scheme_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key);
|
||||||
XFORM_NONGCING MZ_EXTERN Scheme_Object *scheme_eq_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key);
|
XFORM_NONGCING MZ_EXTERN Scheme_Object *scheme_eq_hash_tree_get(Scheme_Hash_Tree *tree, Scheme_Object *key);
|
||||||
MZ_EXTERN intptr_t scheme_hash_tree_next(Scheme_Hash_Tree *tree, intptr_t pos);
|
XFORM_NONGCING MZ_EXTERN intptr_t scheme_hash_tree_next(Scheme_Hash_Tree *tree, intptr_t pos);
|
||||||
MZ_EXTERN int scheme_hash_tree_index(Scheme_Hash_Tree *tree, intptr_t pos, Scheme_Object **_key, Scheme_Object **_val);
|
XFORM_NONGCING MZ_EXTERN int scheme_hash_tree_index(Scheme_Hash_Tree *tree, intptr_t pos, Scheme_Object **_key, Scheme_Object **_val);
|
||||||
MZ_EXTERN int scheme_hash_tree_equal(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2);
|
MZ_EXTERN int scheme_hash_tree_equal(Scheme_Hash_Tree *t1, Scheme_Hash_Tree *t2);
|
||||||
MZ_EXTERN int scheme_is_hash_tree_equal(Scheme_Object *o);
|
MZ_EXTERN int scheme_is_hash_tree_equal(Scheme_Object *o);
|
||||||
MZ_EXTERN int scheme_is_hash_tree_eqv(Scheme_Object *o);
|
MZ_EXTERN int scheme_is_hash_tree_eqv(Scheme_Object *o);
|
||||||
|
|
|
@ -790,7 +790,6 @@ struct Scheme_Hash_Tree
|
||||||
Scheme_Inclhash_Object iso; /* 0x1 flag => equal?-based hashing; 0x2 flag => eqv?-based hashing */
|
Scheme_Inclhash_Object iso; /* 0x1 flag => equal?-based hashing; 0x2 flag => eqv?-based hashing */
|
||||||
intptr_t count;
|
intptr_t count;
|
||||||
struct AVLNode *root;
|
struct AVLNode *root;
|
||||||
Scheme_Object *elems_box; /* vector in a weak box */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCHEME_HASHTR_FLAGS(tr) MZ_OPT_HASH_KEY(&(tr)->iso)
|
#define SCHEME_HASHTR_FLAGS(tr) MZ_OPT_HASH_KEY(&(tr)->iso)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user