hashmap: refactor interface

- `hashmap_insert()` no longer takes key as argument, and
  takes the pointer to be associated with the entry as argument.
- Rename `hashmap_entry_delete` -> `hashmap_delete`.
- Make `user_data` the first argument for `hashmap_walk_func`.
- Other misc renames.
This commit is contained in:
CismonX 2025-03-06 06:40:28 +08:00
parent b585a05c91
commit c2a91d6420
No known key found for this signature in database
GPG key ID: 3094873E29A482FB
5 changed files with 84 additions and 110 deletions

View file

@ -527,7 +527,7 @@ fsck_apply (
entry->name = json_string_value(name_node); entry->name = json_string_value(name_node);
entry->name_len = name_len; entry->name_len = name_len;
*hashmap_insert(assoc_map, key_assoc, hashcode_assoc) = entry; hashmap_insert(assoc_map, hashcode_assoc, entry);
return 0; return 0;
callback: callback:
@ -670,10 +670,8 @@ update_guid (
uint8_t *guid, uint8_t *guid,
unsigned long hashcode unsigned long hashcode
) { ) {
hashmap_entry_delete(guid_map, entry, old_entry_id); hashmap_delete(guid_map, entry, old_entry_id);
hashmap_insert(guid_map, hashcode, entry);
union hashmap_key key = { .ptr = guid };
*hashmap_insert(guid_map, key, hashcode) = entry;
memcpy(entry->guid, guid, UUID_LEN); memcpy(entry->guid, guid, UUID_LEN);
} }
@ -768,13 +766,11 @@ build_maps (
.node = root, .node = root,
.children = children, .children = children,
}; };
union hashmap_key key_id = { .u64 = root_id }; unsigned long hashcode_id = hash_digest(&root_id, sizeof(root_id));
unsigned long hashcode_id = hash_digest(&root_id, sizeof(root_id)); hashmap_insert(id_map, hashcode_id, root_entry);
*hashmap_insert(id_map, key_id, hashcode_id) = root_entry;
union hashmap_key key_guid = { .ptr = root_entry->guid }; unsigned long hashcode_guid = hash_digest(root_entry->guid, UUID_LEN);
unsigned long hashcode_guid = hash_digest(root_entry->guid, UUID_LEN); hashmap_insert(guid_map, hashcode_guid, root_entry);
*hashmap_insert(guid_map, key_guid, hashcode_guid) = root_entry;
struct idmap_iter_ctx iter_ctx = { struct idmap_iter_ctx iter_ctx = {
.id_map = id_map, .id_map = id_map,
@ -879,8 +875,8 @@ free_blcookie (
static void static void
free_entry_cb ( free_entry_cb (
void *entry, void *UNUSED_VAR(user_data),
void *UNUSED_VAR(user_data) void *entry
) { ) {
free(entry); free(entry);
} }
@ -1321,8 +1317,8 @@ maps_iter_cb (
entry->node = node; entry->node = node;
entry->children = children; entry->children = children;
memcpy(entry->guid, guid, UUID_LEN); memcpy(entry->guid, guid, UUID_LEN);
*hashmap_insert(ctx->id_map, key, hashcode) = entry; hashmap_insert(ctx->id_map, hashcode, entry);
*hashmap_insert(ctx->guid_map, key_guid, hashcode_guid) = entry; hashmap_insert(ctx->guid_map, hashcode_guid, entry);
// bookmark bar, mobile bookmarks, other bookmarks, ... // bookmark bar, mobile bookmarks, other bookmarks, ...
if (parent->id == BOOKMARKS_ROOT_ID) { if (parent->id == BOOKMARKS_ROOT_ID) {
@ -1359,7 +1355,7 @@ maps_iter_cb (
entry->name = name; entry->name = name;
entry->name_len = name_len; entry->name_len = name_len;
*hashmap_insert(assoc_map, key_assoc, hashcode_assoc) = entry; hashmap_insert(assoc_map, hashcode_assoc, entry);
end: end:
#ifdef BOOKMARKFS_BACKEND_CHROMIUM_WRITE #ifdef BOOKMARKFS_BACKEND_CHROMIUM_WRITE
@ -2265,9 +2261,7 @@ bookmark_create (
.node = node, .node = node,
.children = is_dir ? json_object_sget(node, "children") : NULL, .children = is_dir ? json_object_sget(node, "children") : NULL,
}; };
hashmap_insert(ctx->id_map, hash_digest(&id, sizeof(id)), entry);
union hashmap_key key = { .u64 = id };
*hashmap_insert(ctx->id_map, key, hash_digest(&id, sizeof(id))) = entry;
void *guid = lctx.guid; void *guid = lctx.guid;
unsigned long hashcode_guid = lctx.hashcode; unsigned long hashcode_guid = lctx.hashcode;
@ -2275,16 +2269,9 @@ bookmark_create (
guid = bctx.guid; guid = bctx.guid;
hashcode_guid = bctx.hashcode; hashcode_guid = bctx.hashcode;
key.ptr = &(struct assocmap_key) { hashmap_insert(ctx->assoc_map, lctx.hashcode, entry);
.parent_id = parent_id,
.name = name,
.name_len = name_len,
};
*hashmap_insert(ctx->assoc_map, key, lctx.hashcode) = entry;
} }
hashmap_insert(ctx->guid_map, hashcode_guid, entry);
key.ptr = guid;
*hashmap_insert(ctx->guid_map, key, hashcode_guid) = entry;
memcpy(entry->guid, guid, UUID_LEN); memcpy(entry->guid, guid, UUID_LEN);
ctx->dirty = DIRTY_LEVEL_DATA; ctx->dirty = DIRTY_LEVEL_DATA;
@ -2344,10 +2331,10 @@ bookmark_delete (
long guidmap_entry_id = lctx.entry_id; long guidmap_entry_id = lctx.entry_id;
if (!(ctx->flags & BACKEND_FILENAME_GUID)) { if (!(ctx->flags & BACKEND_FILENAME_GUID)) {
guidmap_entry_id = -1; guidmap_entry_id = -1;
hashmap_entry_delete(ctx->assoc_map, entry, lctx.entry_id); hashmap_delete(ctx->assoc_map, entry, lctx.entry_id);
} }
hashmap_entry_delete(ctx->guid_map, entry, guidmap_entry_id); hashmap_delete(ctx->guid_map, entry, guidmap_entry_id);
hashmap_entry_delete(ctx->id_map, entry, -1); hashmap_delete(ctx->id_map, entry, -1);
free(entry); free(entry);
// Remove from store // Remove from store
@ -2566,10 +2553,10 @@ bookmark_rename (
long new_guidmap_entry_id = new_lctx.entry_id; long new_guidmap_entry_id = new_lctx.entry_id;
if (!filename_is_guid) { if (!filename_is_guid) {
new_guidmap_entry_id = -1; new_guidmap_entry_id = -1;
hashmap_entry_delete(ctx->assoc_map, new_entry, new_lctx.entry_id); hashmap_delete(ctx->assoc_map, new_entry, new_lctx.entry_id);
} }
hashmap_entry_delete(ctx->guid_map, new_entry, new_guidmap_entry_id); hashmap_delete(ctx->guid_map, new_entry, new_guidmap_entry_id);
hashmap_entry_delete(ctx->id_map, new_entry, -1); hashmap_delete(ctx->id_map, new_entry, -1);
free(new_entry); free(new_entry);
} }
@ -2577,16 +2564,8 @@ bookmark_rename (
update_guid(old_entry, ctx->guid_map, old_lctx.entry_id, new_lctx.guid, update_guid(old_entry, ctx->guid_map, old_lctx.entry_id, new_lctx.guid,
new_lctx.hashcode); new_lctx.hashcode);
} else { } else {
hashmap_entry_delete(ctx->assoc_map, old_entry, old_lctx.entry_id); hashmap_delete(ctx->assoc_map, old_entry, old_lctx.entry_id);
hashmap_insert(ctx->assoc_map, new_lctx.hashcode, old_entry);
union hashmap_key key = {
.ptr = &(struct assocmap_key) {
.parent_id = new_parent_id,
.name = old_entry->name,
.name_len = new_name_len,
},
};
*hashmap_insert(ctx->assoc_map, key, new_lctx.hashcode) = old_entry;
} }
ctx->dirty = DIRTY_LEVEL_DATA; ctx->dirty = DIRTY_LEVEL_DATA;

View file

@ -533,7 +533,7 @@ fsck_apply (
dentry->name_len = name_len; dentry->name_len = name_len;
memcpy(dentry->name, name, name_len); memcpy(dentry->name, name, name_len);
*hashmap_insert(map, key, hashcode) = dentry; hashmap_insert(map, hashcode, dentry);
goto end; goto end;
callback: callback:
@ -2347,7 +2347,7 @@ bookmark_check_cb (
map = hashmap_create(dentmap_comp, dentmap_hash); map = hashmap_create(dentmap_comp, dentmap_hash);
ctx->dentry_map = map; ctx->dentry_map = map;
} }
*hashmap_insert(map, key, hashcode) = dentry; hashmap_insert(map, hashcode, dentry);
return 0; return 0;
} }
if (dentry->id == (uint64_t)id) { if (dentry->id == (uint64_t)id) {
@ -2457,7 +2457,7 @@ bookmark_list_cb (
dentry->name_len = name_len; dentry->name_len = name_len;
memcpy(dentry->name, name, name_len); memcpy(dentry->name, name, name_len);
*hashmap_insert(map, key, hashcode) = dentry; hashmap_insert(map, hashcode, dentry);
} }
return ctx->status; return ctx->status;
@ -2547,8 +2547,8 @@ free_dentmap (
static void static void
free_dentmap_entry ( free_dentmap_entry (
void *entry, void *UNUSED_VAR(user_data),
void *UNUSED_VAR(user_data) void *entry
) { ) {
struct bookmark_dentry *dentry = entry; struct bookmark_dentry *dentry = entry;

View file

@ -458,7 +458,7 @@ bm_fh_free (
struct fs_file_handle *fh, struct fs_file_handle *fh,
long entry_id long entry_id
) { ) {
hashmap_entry_delete(ctx.fh_map, fh, entry_id); hashmap_delete(ctx.fh_map, fh, entry_id);
free(fh); free(fh);
} }
@ -493,8 +493,7 @@ bm_fh_new (
.id = id, .id = id,
.refcount = 1, .refcount = 1,
}; };
union hashmap_key key = { .u64 = id }; hashmap_insert(ctx.fh_map, hashcode, fh);
*hashmap_insert(ctx.fh_map, key, hashcode) = fh;
return fh; return fh;
} }

View file

@ -155,14 +155,14 @@ count_tz (
*/ */
static int static int
find_entry ( find_entry (
struct hashmap const *h, struct hashmap const *map,
void const *entry, void const *entry,
struct bucket **home_ptr struct bucket **home_ptr
) { ) {
unsigned exp = h->exp; unsigned exp = map->exp;
unsigned long hashcode = h->entry_hash(entry); unsigned long hashcode = map->entry_hash(entry);
size_t hash_idx = HASH_TO_IDX(hashcode, exp); size_t hash_idx = HASH_TO_IDX(hashcode, exp);
struct bucket *home = h->buckets + hash_idx; struct bucket *home = map->buckets + hash_idx;
unsigned long hop = home->bits; unsigned long hop = home->bits;
unsigned long hash_mask = BUCKET_HASH_MASK(exp); unsigned long hash_mask = BUCKET_HASH_MASK(exp);
@ -172,10 +172,10 @@ find_entry (
debug_assert(hop_idx < exp); debug_assert(hop_idx < exp);
struct bucket *b = home + hop_idx; struct bucket *b = home + hop_idx;
if ((b->bits & hash_mask) != (hashcode << h->exp)) { if ((b->bits & hash_mask) != (hashcode << map->exp)) {
continue; continue;
} }
if (entry != h->buckets[b - h->buckets].entry) { if (entry != map->buckets[b - map->buckets].entry) {
continue; continue;
} }
@ -241,10 +241,10 @@ make_room (
static int static int
rehash ( rehash (
struct hashmap *h, struct hashmap *map,
bool grow bool grow
) { ) {
unsigned new_exp = h->exp; unsigned new_exp = map->exp;
if (grow) { if (grow) {
if (unlikely(++new_exp > EXP_MAX)) { if (unlikely(++new_exp > EXP_MAX)) {
log_puts("rehash(): hashmap size exceeds max limit"); log_puts("rehash(): hashmap size exceeds max limit");
@ -257,9 +257,9 @@ rehash (
size_t new_nbuckets = BUCKET_CNT(new_exp); size_t new_nbuckets = BUCKET_CNT(new_exp);
struct bucket *new_buckets = xcalloc(new_nbuckets, sizeof(struct bucket)); struct bucket *new_buckets = xcalloc(new_nbuckets, sizeof(struct bucket));
struct bucket *old_buckets_end = h->buckets + h->num_buckets; struct bucket *old_b_end = map->buckets + map->num_buckets;
unsigned long new_hop_mask = BUCKET_HOP_MASK(new_exp); unsigned long new_hop_mask = BUCKET_HOP_MASK(new_exp);
for (struct bucket *old_b = h->buckets; old_b < old_buckets_end; ++old_b) { for (struct bucket *old_b = map->buckets; old_b < old_b_end; ++old_b) {
void *old_e = old_b->entry; void *old_e = old_b->entry;
if (old_e == NULL) { if (old_e == NULL) {
continue; continue;
@ -267,7 +267,7 @@ rehash (
// Cannot trivially deduce hashcode from old hash fragment, // Cannot trivially deduce hashcode from old hash fragment,
// since we have to find its home bucket. // since we have to find its home bucket.
unsigned long hashcode = h->entry_hash(old_e); unsigned long hashcode = map->entry_hash(old_e);
size_t new_hash_idx = HASH_TO_IDX(hashcode, new_exp); size_t new_hash_idx = HASH_TO_IDX(hashcode, new_exp);
struct bucket *new_home = new_buckets + new_hash_idx; struct bucket *new_home = new_buckets + new_hash_idx;
@ -283,10 +283,10 @@ rehash (
new_b->entry = old_e; new_b->entry = old_e;
} }
free(h->buckets); free(map->buckets);
h->buckets = new_buckets; map->buckets = new_buckets;
h->num_buckets = new_nbuckets; map->num_buckets = new_nbuckets;
h->exp = new_exp; map->exp = new_exp;
return 0; return 0;
fail: fail:
@ -328,34 +328,34 @@ hashmap_create (
void void
hashmap_destroy ( hashmap_destroy (
struct hashmap *h struct hashmap *map
) { ) {
if (h == NULL) { if (map == NULL) {
return; return;
} }
free(h->buckets); free(map->buckets);
free(h); free(map);
} }
void void
hashmap_foreach ( hashmap_foreach (
struct hashmap const *h, struct hashmap const *map,
hashmap_walk_func *walk_func, hashmap_walk_func *walk_func,
void *user_data void *user_data
) { ) {
struct bucket *end = h->buckets + h->num_buckets; struct bucket *end = map->buckets + map->num_buckets;
for (struct bucket *b = h->buckets; b < end; ++b) { for (struct bucket *b = map->buckets; b < end; ++b) {
void *entry = b->entry; void *entry = b->entry;
if (entry == NULL) { if (entry == NULL) {
continue; continue;
} }
walk_func(b->entry, user_data); walk_func(user_data, b->entry);
} }
} }
void void
hashmap_entry_delete ( hashmap_delete (
struct hashmap *h, struct hashmap *h,
void const *entry, void const *entry,
long entry_id long entry_id
@ -386,42 +386,44 @@ hashmap_entry_delete (
} }
} }
void ** void
hashmap_insert ( hashmap_insert (
struct hashmap *h, struct hashmap *map,
union hashmap_key key, unsigned long hashcode,
unsigned long hashcode void *entry
) { ) {
unsigned exp = h->exp; unsigned exp = map->exp;
size_t hash_idx = HASH_TO_IDX(hashcode, exp); size_t hash_idx = HASH_TO_IDX(hashcode, exp);
struct bucket *home = h->buckets + hash_idx; struct bucket *home = map->buckets + hash_idx;
int hop_idx = make_room(home, h->buckets + h->num_buckets, exp); int hop_idx = make_room(home, map->buckets + map->num_buckets, exp);
if (unlikely(hop_idx < 0)) { if (unlikely(hop_idx < 0)) {
debug_printf("hashmap_insert(): rehashing (%zu/%zu)", debug_printf("hashmap_insert(): rehashing (%zu/%zu)",
h->num_used, h->num_buckets - (exp - 1)); map->num_used, map->num_buckets - (exp - 1));
xassert(0 == rehash(h, true)); xassert(0 == rehash(map, true));
return hashmap_insert(h, key, hashcode); hashmap_insert(map, hashcode, entry);
return;
} }
BIT_SET(home->bits, hop_idx); BIT_SET(home->bits, hop_idx);
struct bucket *b = home + hop_idx; struct bucket *b = home + hop_idx;
b->bits = (b->bits & BUCKET_HOP_MASK(exp)) | (hashcode << exp); b->bits = (b->bits & BUCKET_HOP_MASK(exp)) | (hashcode << exp);
++h->num_used; ++map->num_used;
return &b->entry; debug_assert(entry != NULL);
b->entry = entry;
} }
void * void *
hashmap_search ( hashmap_search (
struct hashmap const *h, struct hashmap const *map,
union hashmap_key key, union hashmap_key key,
unsigned long hashcode, unsigned long hashcode,
unsigned long *entry_id_ptr unsigned long *entry_id_ptr
) { ) {
unsigned exp = h->exp; unsigned exp = map->exp;
size_t hash_idx = HASH_TO_IDX(hashcode, exp); size_t hash_idx = HASH_TO_IDX(hashcode, exp);
struct bucket *home = h->buckets + hash_idx; struct bucket *home = map->buckets + hash_idx;
unsigned long hop = home->bits; unsigned long hop = home->bits;
unsigned long hash_mask = BUCKET_HASH_MASK(exp); unsigned long hash_mask = BUCKET_HASH_MASK(exp);
@ -438,7 +440,7 @@ hashmap_search (
} }
void *e = b->entry; void *e = b->entry;
debug_assert(e != NULL); debug_assert(e != NULL);
if (0 != h->entry_comp(key, e)) { if (0 != map->entry_comp(key, e)) {
continue; continue;
} }
if (entry_id_ptr != NULL) { if (entry_id_ptr != NULL) {

View file

@ -33,8 +33,8 @@ union hashmap_key {
}; };
typedef void (hashmap_walk_func) ( typedef void (hashmap_walk_func) (
void *entry, void *user_data,
void *user_data void *entry
); );
/** /**
@ -67,7 +67,7 @@ hashmap_create (
void void
hashmap_destroy ( hashmap_destroy (
struct hashmap *h struct hashmap *map
); );
/** /**
@ -76,7 +76,7 @@ hashmap_destroy (
*/ */
void void
hashmap_foreach ( hashmap_foreach (
struct hashmap const *h, struct hashmap const *map,
hashmap_walk_func *walk_func, hashmap_walk_func *walk_func,
void *user_data void *user_data
); );
@ -95,7 +95,7 @@ hashmap_foreach (
*/ */
void * void *
hashmap_search ( hashmap_search (
struct hashmap const *h, struct hashmap const *map,
union hashmap_key key, union hashmap_key key,
unsigned long hashcode, unsigned long hashcode,
unsigned long *entry_id_ptr unsigned long *entry_id_ptr
@ -105,16 +105,12 @@ hashmap_search (
* Insert an entry into the hashmap. * Insert an entry into the hashmap.
* *
* Invalidates all entry IDs given by previous hashmap_search() calls. * Invalidates all entry IDs given by previous hashmap_search() calls.
*
* Returns a pointer to the inserted entry.
* The entry must be set to a non-NULL value using this pointer
* prior to any further search/insert/delete calls on this hashmap.
*/ */
void ** void
hashmap_insert ( hashmap_insert (
struct hashmap *h, struct hashmap *map,
union hashmap_key key, unsigned long hashcode,
unsigned long hashcode void *entry
); );
/** /**
@ -124,12 +120,10 @@ hashmap_insert (
* The entry_id argument should either be the value given by the * The entry_id argument should either be the value given by the
* hashmap_search() or hashmap_insert() function call where the * hashmap_search() or hashmap_insert() function call where the
* entry is returned from, or -1 (less efficient). * entry is returned from, or -1 (less efficient).
*
* Unlike hashmap_insert(), previously entry IDs are not affected.
*/ */
void void
hashmap_entry_delete ( hashmap_delete (
struct hashmap *h, struct hashmap *map,
void const *entry, void const *entry,
long entry_id long entry_id
); );