diff --git a/src/.clang-format b/src/.clang-format index b19bb8a68f1..badf59ab108 100644 --- a/src/.clang-format +++ b/src/.clang-format @@ -57,6 +57,7 @@ ForEachMacros: - hash_table_foreach - hash_table_foreach_remove + - hash_table_u64_foreach - rb_tree_foreach - rb_tree_foreach_rev diff --git a/src/util/hash_table.c b/src/util/hash_table.c index a76ebbc039e..4a6cedc2b4b 100644 --- a/src/util/hash_table.c +++ b/src/util/hash_table.c @@ -960,3 +960,49 @@ _mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key) FREE(_key); } } + + +/* + * Iterates in order ("freed key", "deleted key", regular entries...) + */ +struct hash_entry_u64 +_mesa_hash_table_u64_next_entry(struct hash_table_u64 *ht, + struct hash_entry_u64 *ent) +{ + /* First entry: freed key */ + if (!ent && ht->freed_key_data) { + return (struct hash_entry_u64){ + .key = FREED_KEY_VALUE, + .data = ht->freed_key_data, + }; + } + + /* Second entry: deleted key */ + if ((!ent || ent->key == FREED_KEY_VALUE) && ht->deleted_key_data) { + return (struct hash_entry_u64){ + .key = DELETED_KEY_VALUE, + .data = ht->deleted_key_data, + }; + } + + /* All other entries: regular */ + struct hash_entry *next = + _mesa_hash_table_next_entry(ht->table, ent ? ent->_entry : NULL); + + if (!next) + return (struct hash_entry_u64){.data = NULL}; + + uint64_t key; + if (sizeof(void *) == 8) { + key = (uintptr_t)next->key; + } else { + const struct hash_key_u64 *_key = next->key; + key = _key->value; + } + + return (struct hash_entry_u64){ + .key = key, + .data = next->data, + ._entry = next, + }; +} diff --git a/src/util/hash_table.h b/src/util/hash_table.h index 002d6c58873..2091ad01580 100644 --- a/src/util/hash_table.h +++ b/src/util/hash_table.h @@ -171,6 +171,12 @@ struct hash_table_u64 { void *deleted_key_data; }; +struct hash_entry_u64 { + uint64_t key; + void *data; + struct hash_entry *_entry; +}; + struct hash_table_u64 * _mesa_hash_table_u64_create(void *mem_ctx); @@ -190,6 +196,22 @@ _mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key); void _mesa_hash_table_u64_clear(struct hash_table_u64 *ht); +struct hash_entry_u64 +_mesa_hash_table_u64_next_entry(struct hash_table_u64 *ht, + struct hash_entry_u64 *ent); + +/** + * This foreach function is safe against deletion (which just replaces + * an entry's data with the deleted marker), but not against insertion + * (which may rehash the table, making entry a dangling pointer). + */ +#define hash_table_u64_foreach(ht, entry) \ + for (struct hash_entry_u64 entry = \ + _mesa_hash_table_u64_next_entry(ht, NULL); \ + entry.data != NULL; \ + entry = _mesa_hash_table_u64_next_entry(ht, &entry)) + + #ifdef __cplusplus } /* extern C */ #endif