libdrgn: hash_table: move entry_to_key to DEFINE_HASH_TABLE_FUNCTIONS()

DEFINE_HASH_TABLE_TYPE() doesn't actually need to know the key type.
Move that argument (and some of the derived constants) to
DEFINE_HASH_TABLE_FUNCTIONS(). This will allow recursive hash table
types. As a nice side effect, it also reduces the size of common header
files.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
Omar Sandoval 2021-10-11 13:01:07 -07:00
parent 802d6cc9ff
commit 1339dc6a2f
8 changed files with 157 additions and 132 deletions

View File

@ -480,6 +480,23 @@ err:
DEFINE_VECTOR_FUNCTIONS(drgn_debug_info_module_vector)
struct drgn_debug_info_module_key {
const void *build_id;
size_t build_id_len;
uint64_t start, end;
};
static inline struct drgn_debug_info_module_key
drgn_debug_info_module_key(struct drgn_debug_info_module * const *entry)
{
return (struct drgn_debug_info_module_key){
.build_id = (*entry)->build_id,
.build_id_len = (*entry)->build_id_len,
.start = (*entry)->start,
.end = (*entry)->end,
};
}
static inline struct hash_pair
drgn_debug_info_module_key_hash_pair(const struct drgn_debug_info_module_key *key)
{
@ -497,11 +514,11 @@ drgn_debug_info_module_key_eq(const struct drgn_debug_info_module_key *a,
a->start == b->start && a->end == b->end);
}
DEFINE_HASH_TABLE_FUNCTIONS(drgn_debug_info_module_table,
drgn_debug_info_module_key,
drgn_debug_info_module_key_hash_pair,
drgn_debug_info_module_key_eq)
DEFINE_HASH_TABLE_FUNCTIONS(c_string_set, c_string_key_hash_pair,
c_string_key_eq)
DEFINE_HASH_SET_FUNCTIONS(c_string_set, c_string_key_hash_pair, c_string_key_eq)
/**
* @c Dwfl_Callbacks::find_elf() implementation.
@ -2566,8 +2583,7 @@ out:
return err;
}
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_type_map, ptr_key_hash_pair,
scalar_key_eq)
DEFINE_HASH_MAP_FUNCTIONS(drgn_dwarf_type_map, ptr_key_hash_pair, scalar_key_eq)
/**
* Return whether a DWARF DIE is little-endian.

View File

@ -244,25 +244,8 @@ struct drgn_error *drgn_find_die_ancestors(Dwarf_Die *die, Dwarf_Die **dies_ret,
size_t *length_ret)
__attribute__((__nonnull__(2, 3)));
struct drgn_debug_info_module_key {
const void *build_id;
size_t build_id_len;
uint64_t start, end;
};
static inline struct drgn_debug_info_module_key
drgn_debug_info_module_key(struct drgn_debug_info_module * const *entry)
{
return (struct drgn_debug_info_module_key){
.build_id = (*entry)->build_id,
.build_id_len = (*entry)->build_id_len,
.start = (*entry)->start,
.end = (*entry)->end,
};
}
DEFINE_HASH_TABLE_TYPE(drgn_debug_info_module_table,
struct drgn_debug_info_module *,
drgn_debug_info_module_key)
struct drgn_debug_info_module *)
DEFINE_HASH_SET_TYPE(c_string_set, const char *)

View File

@ -185,10 +185,17 @@ struct drgn_dwarf_index_pending_die {
DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_pending_die_vector)
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_die_map, string_hash_pair,
string_eq)
DEFINE_HASH_MAP_FUNCTIONS(drgn_dwarf_index_die_map, string_hash_pair, string_eq)
DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_die_vector)
static inline uintptr_t
drgn_dwarf_index_specification_to_key(const struct drgn_dwarf_index_specification *entry)
{
return entry->declaration;
}
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_specification_map,
drgn_dwarf_index_specification_to_key,
int_key_hash_pair, scalar_key_eq)
static inline size_t hash_pair_to_shard(struct hash_pair hp)

View File

@ -123,15 +123,8 @@ struct drgn_dwarf_index_specification {
uintptr_t addr;
};
static inline uintptr_t
drgn_dwarf_index_specification_to_key(const struct drgn_dwarf_index_specification *entry)
{
return entry->declaration;
}
DEFINE_HASH_TABLE_TYPE(drgn_dwarf_index_specification_map,
struct drgn_dwarf_index_specification,
drgn_dwarf_index_specification_to_key)
struct drgn_dwarf_index_specification)
DEFINE_VECTOR_TYPE(drgn_dwarf_index_cu_vector, struct drgn_dwarf_index_cu)

View File

@ -375,15 +375,8 @@ static inline unsigned int table##_chunk_occupied(struct table##_chunk *chunk) \
*
* @sa DEFINE_HASH_TABLE()
*/
#define DEFINE_HASH_TABLE_TYPE(table, entry_type, entry_to_key) \
#define DEFINE_HASH_TABLE_TYPE(table, entry_type) \
typedef typeof(entry_type) table##_entry_type; \
typedef typeof(entry_to_key((table##_entry_type *)0)) table##_key_type; \
\
static inline table##_key_type \
table##_entry_to_key(const table##_entry_type *entry) \
{ \
return entry_to_key(entry); \
} \
\
enum { \
/* \
@ -395,6 +388,79 @@ enum { \
table##_vector_policy = sizeof(table##_entry_type) >= 24, \
}; \
\
struct table { \
struct table##_chunk *chunks; \
struct { \
/* \
* The vector storage policy stores 32-bit indices, so we only \
* need 32-bit sizes. \
*/ \
uint32_t chunk_mask; \
uint32_t size; \
/* Allocated together with chunks. */ \
table##_entry_type *entries; \
} vector[table##_vector_policy]; \
struct { \
size_t chunk_mask; \
size_t size; \
uintptr_t first_packed; \
} basic[!table##_vector_policy]; \
};
/*
* Common search function implementation returning an item iterator. This is
* shared by key lookups and index lookups.
*/
#define HASH_TABLE_SEARCH_IMPL(table, func, key_type, item_to_key, eq_func) \
static struct table##_iterator table##_##func(struct table *table, \
const key_type *key, \
struct hash_pair hp) \
{ \
const size_t delta = hash_table_probe_delta(hp); \
size_t index = hp.first; \
for (size_t tries = 0; tries <= table##_chunk_mask(table); tries++) { \
struct table##_chunk *chunk = \
&table->chunks[index & table##_chunk_mask(table)]; \
if (sizeof(*chunk) > 64) \
__builtin_prefetch(&chunk->items[8]); \
unsigned int mask = table##_chunk_match(chunk, hp.second), i; \
for_each_bit(i, mask) { \
table##_item_type *item = &chunk->items[i]; \
key_type item_key = item_to_key(table, item); \
if (likely(eq_func(key, &item_key))) { \
return (struct table##_iterator){ \
.item = item, \
.index = i, \
}; \
} \
} \
if (likely(chunk->outbound_overflow_count == 0)) \
break; \
index += delta; \
} \
return (struct table##_iterator){}; \
}
#define HASH_TABLE_SEARCH_BY_INDEX_ITEM_TO_KEY(table, item) (*(item)->index)
/**
* Define the functions for a hash table.
*
* The hash table type must have already been defined with @ref
* DEFINE_HASH_TABLE_TYPE().
*
* Unless the type and function definitions must be in separate places, use @ref
* DEFINE_HASH_TABLE() instead.
*/
#define DEFINE_HASH_TABLE_FUNCTIONS(table, entry_to_key, hash_func, eq_func) \
typedef typeof(entry_to_key((table##_entry_type *)0)) table##_key_type; \
\
static inline table##_key_type \
table##_entry_to_key(const table##_entry_type *entry) \
{ \
return entry_to_key(entry); \
} \
\
/* \
* Item stored in a chunk. \
* \
@ -489,73 +555,6 @@ struct table##_iterator { \
}; \
}; \
\
struct table { \
struct table##_chunk *chunks; \
struct { \
/* \
* The vector storage policy stores 32-bit indices, so we only \
* need 32-bit sizes. \
*/ \
uint32_t chunk_mask; \
uint32_t size; \
/* Allocated together with chunks. */ \
table##_entry_type *entries; \
} vector[table##_vector_policy]; \
struct { \
size_t chunk_mask; \
size_t size; \
uintptr_t first_packed; \
} basic[!table##_vector_policy]; \
};
/*
* Common search function implementation returning an item iterator. This is
* shared by key lookups and index lookups.
*/
#define HASH_TABLE_SEARCH_IMPL(table, func, key_type, item_to_key, eq_func) \
static struct table##_iterator table##_##func(struct table *table, \
const key_type *key, \
struct hash_pair hp) \
{ \
const size_t delta = hash_table_probe_delta(hp); \
size_t index = hp.first; \
for (size_t tries = 0; tries <= table##_chunk_mask(table); tries++) { \
struct table##_chunk *chunk = \
&table->chunks[index & table##_chunk_mask(table)]; \
if (sizeof(*chunk) > 64) \
__builtin_prefetch(&chunk->items[8]); \
unsigned int mask = table##_chunk_match(chunk, hp.second), i; \
for_each_bit(i, mask) { \
table##_item_type *item = &chunk->items[i]; \
key_type item_key = item_to_key(table, item); \
if (likely(eq_func(key, &item_key))) { \
return (struct table##_iterator){ \
.item = item, \
.index = i, \
}; \
} \
} \
if (likely(chunk->outbound_overflow_count == 0)) \
break; \
index += delta; \
} \
return (struct table##_iterator){}; \
}
#define HASH_TABLE_SEARCH_BY_INDEX_ITEM_TO_KEY(table, item) (*(item)->index)
/**
* Define the functions for a hash table.
*
* The hash table type must have already been defined with @ref
* DEFINE_HASH_TABLE_TYPE().
*
* Unless the type and function definitions must be in separate places, use @ref
* DEFINE_HASH_TABLE() instead.
*
* @sa DEFINE_HASH_TABLE()
*/
#define DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func) \
static inline struct hash_pair table##_hash(const table##_key_type *key) \
{ \
return hash_func(key); \
@ -1425,24 +1424,38 @@ static struct table##_iterator table##_next(struct table##_iterator it) \
* *</tt> and returns a @c bool.
*/
#define DEFINE_HASH_TABLE(table, entry_type, entry_to_key, hash_func, eq_func) \
DEFINE_HASH_TABLE_TYPE(table, entry_type, entry_to_key) \
DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func)
#define HASH_MAP_ENTRY_TO_KEY(entry) ((entry)->key)
DEFINE_HASH_TABLE_TYPE(table, entry_type) \
DEFINE_HASH_TABLE_FUNCTIONS(table, entry_to_key, hash_func, eq_func)
/**
* Define a hash map type without defining its functions.
*
* The functions are defined with @ref DEFINE_HASH_TABLE_FUNCTIONS().
* The functions are defined with @ref DEFINE_HASH_MAP_FUNCTIONS().
*
* @sa DEFINE_HASH_MAP(), DEFINE_HASH_TABLE_TYPE()
*/
#define DEFINE_HASH_MAP_TYPE(table, key_type, value_type) \
struct table##_entry { \
typeof(key_type) key; \
typeof(value_type) value; \
}; \
DEFINE_HASH_TABLE_TYPE(table, struct table##_entry, HASH_MAP_ENTRY_TO_KEY)
#define DEFINE_HASH_MAP_TYPE(table, key_type, value_type) \
struct table##_entry { \
typeof(key_type) key; \
typeof(value_type) value; \
}; \
DEFINE_HASH_TABLE_TYPE(table, struct table##_entry)
#define HASH_MAP_ENTRY_TO_KEY(entry) ((entry)->key)
/**
* Define the functions for a hash map.
*
* The hash map type must have already been defined with @ref
* DEFINE_HASH_MAP_TYPE().
*
* Unless the type and function definitions must be in separate places, use @ref
* DEFINE_HASH_MAP() instead.
*
* @sa DEFINE_HASH_TABLE_FUNCTIONS
*/
#define DEFINE_HASH_MAP_FUNCTIONS(table, hash_func, eq_func) \
DEFINE_HASH_TABLE_FUNCTIONS(table, HASH_MAP_ENTRY_TO_KEY, hash_func, eq_func)
/**
* Define a hash map interface.
@ -1466,19 +1479,32 @@ DEFINE_HASH_TABLE_TYPE(table, struct table##_entry, HASH_MAP_ENTRY_TO_KEY)
*/
#define DEFINE_HASH_MAP(table, key_type, value_type, hash_func, eq_func) \
DEFINE_HASH_MAP_TYPE(table, key_type, value_type) \
DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func)
#define HASH_SET_ENTRY_TO_KEY(entry) (*(entry))
DEFINE_HASH_MAP_FUNCTIONS(table, hash_func, eq_func)
/**
* Define a hash set type without defining its functions.
*
* The functions are defined with @ref DEFINE_HASH_TABLE_FUNCTIONS().
* The functions are defined with @ref DEFINE_HASH_SET_FUNCTIONS().
*
* @sa DEFINE_HASH_SET(), DEFINE_HASH_TABLE_TYPE()
*/
#define DEFINE_HASH_SET_TYPE(table, key_type) \
DEFINE_HASH_TABLE_TYPE(table, key_type, HASH_SET_ENTRY_TO_KEY)
#define DEFINE_HASH_SET_TYPE DEFINE_HASH_TABLE_TYPE
#define HASH_SET_ENTRY_TO_KEY(entry) (*(entry))
/**
* Define the functions for a hash set.
*
* The hash set type must have already been defined with @ref
* DEFINE_HASH_SET_TYPE().
*
* Unless the type and function definitions must be in separate places, use @ref
* DEFINE_HASH_SET() instead.
*
* @sa DEFINE_HASH_TABLE_FUNCTIONS
*/
#define DEFINE_HASH_SET_FUNCTIONS(table, hash_func, eq_func) \
DEFINE_HASH_TABLE_FUNCTIONS(table, HASH_SET_ENTRY_TO_KEY, hash_func, eq_func)
/**
* Define a hash set interface.
@ -1494,7 +1520,7 @@ DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func)
*/
#define DEFINE_HASH_SET(table, key_type, hash_func, eq_func) \
DEFINE_HASH_SET_TYPE(table, key_type) \
DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func)
DEFINE_HASH_SET_FUNCTIONS(table, hash_func, eq_func)
/**
* Empty hash table initializer.

View File

@ -32,7 +32,7 @@
#include "util.h"
DEFINE_VECTOR_FUNCTIONS(drgn_prstatus_vector)
DEFINE_HASH_TABLE_FUNCTIONS(drgn_prstatus_map, int_key_hash_pair, scalar_key_eq)
DEFINE_HASH_MAP_FUNCTIONS(drgn_prstatus_map, int_key_hash_pair, scalar_key_eq)
static Elf_Type note_header_type(GElf_Phdr *phdr)
{

View File

@ -7,7 +7,7 @@
#include "../vector.h"
#include "../util.h"
DEFINE_HASH_TABLE_FUNCTIONS(pyobjectp_set, ptr_key_hash_pair, scalar_key_eq)
DEFINE_HASH_SET_FUNCTIONS(pyobjectp_set, ptr_key_hash_pair, scalar_key_eq)
int Program_hold_object(Program *prog, PyObject *obj)
{

View File

@ -170,10 +170,10 @@ static bool drgn_member_key_eq(const struct drgn_member_key *a,
(!a->name_len || memcmp(a->name, b->name, a->name_len) == 0));
}
DEFINE_HASH_TABLE_FUNCTIONS(drgn_member_map, drgn_member_key_hash_pair,
drgn_member_key_eq)
DEFINE_HASH_MAP_FUNCTIONS(drgn_member_map, drgn_member_key_hash_pair,
drgn_member_key_eq)
DEFINE_HASH_TABLE_FUNCTIONS(drgn_type_set, ptr_key_hash_pair, scalar_key_eq)
DEFINE_HASH_SET_FUNCTIONS(drgn_type_set, ptr_key_hash_pair, scalar_key_eq)
LIBDRGN_PUBLIC struct drgn_error *
drgn_member_object(struct drgn_type_member *member,
@ -329,8 +329,8 @@ static bool drgn_type_dedupe_eq(struct drgn_type * const *entry_a,
* We don't deduplicate types with members, parameters, template parameters, or
* enumerators, so the hash and comparison functions ignore those.
*/
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dedupe_type_set, drgn_type_dedupe_hash_pair,
drgn_type_dedupe_eq)
DEFINE_HASH_SET_FUNCTIONS(drgn_dedupe_type_set, drgn_type_dedupe_hash_pair,
drgn_type_dedupe_eq)
DEFINE_VECTOR_FUNCTIONS(drgn_typep_vector)