|
|
@ -42,6 +42,7 @@ |
|
|
|
struct grpc_mdstr_hash_table { |
|
|
|
struct grpc_mdstr_hash_table { |
|
|
|
gpr_refcount refs; |
|
|
|
gpr_refcount refs; |
|
|
|
size_t num_entries; |
|
|
|
size_t num_entries; |
|
|
|
|
|
|
|
size_t size; |
|
|
|
grpc_mdstr_hash_table_entry* entries; |
|
|
|
grpc_mdstr_hash_table_entry* entries; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -50,13 +51,13 @@ struct grpc_mdstr_hash_table { |
|
|
|
static size_t grpc_mdstr_hash_table_find_index( |
|
|
|
static size_t grpc_mdstr_hash_table_find_index( |
|
|
|
const grpc_mdstr_hash_table* table, const grpc_mdstr* key, |
|
|
|
const grpc_mdstr_hash_table* table, const grpc_mdstr* key, |
|
|
|
bool find_empty) { |
|
|
|
bool find_empty) { |
|
|
|
for (size_t i = 0; i < table->num_entries; ++i) { |
|
|
|
for (size_t i = 0; i < table->size; ++i) { |
|
|
|
const size_t idx = (key->hash + i * i) % table->num_entries; |
|
|
|
const size_t idx = (key->hash + i * i) % table->size; |
|
|
|
if (table->entries[idx].key == NULL) |
|
|
|
if (table->entries[idx].key == NULL) |
|
|
|
return find_empty ? idx : table->num_entries; |
|
|
|
return find_empty ? idx : table->size; |
|
|
|
if (table->entries[idx].key == key) return idx; |
|
|
|
if (table->entries[idx].key == key) return idx; |
|
|
|
} |
|
|
|
} |
|
|
|
return table->num_entries; // Not found.
|
|
|
|
return table->size; // Not found.
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void grpc_mdstr_hash_table_add( |
|
|
|
static void grpc_mdstr_hash_table_add( |
|
|
@ -65,7 +66,7 @@ static void grpc_mdstr_hash_table_add( |
|
|
|
GPR_ASSERT(value != NULL); |
|
|
|
GPR_ASSERT(value != NULL); |
|
|
|
const size_t idx = |
|
|
|
const size_t idx = |
|
|
|
grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */); |
|
|
|
grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */); |
|
|
|
GPR_ASSERT(idx != table->num_entries); // Table should never be full.
|
|
|
|
GPR_ASSERT(idx != table->size); // Table should never be full.
|
|
|
|
grpc_mdstr_hash_table_entry* entry = &table->entries[idx]; |
|
|
|
grpc_mdstr_hash_table_entry* entry = &table->entries[idx]; |
|
|
|
entry->key = GRPC_MDSTR_REF(key); |
|
|
|
entry->key = GRPC_MDSTR_REF(key); |
|
|
|
entry->value = vtable->copy_value(value); |
|
|
|
entry->value = vtable->copy_value(value); |
|
|
@ -77,11 +78,12 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( |
|
|
|
grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table)); |
|
|
|
grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table)); |
|
|
|
memset(table, 0, sizeof(*table)); |
|
|
|
memset(table, 0, sizeof(*table)); |
|
|
|
gpr_ref_init(&table->refs, 1); |
|
|
|
gpr_ref_init(&table->refs, 1); |
|
|
|
|
|
|
|
table->num_entries = num_entries; |
|
|
|
// Quadratic probing gets best performance when the table is no more
|
|
|
|
// Quadratic probing gets best performance when the table is no more
|
|
|
|
// than half full.
|
|
|
|
// than half full.
|
|
|
|
table->num_entries = num_entries * 2; |
|
|
|
table->size = num_entries * 2; |
|
|
|
const size_t entry_size = |
|
|
|
const size_t entry_size = |
|
|
|
sizeof(grpc_mdstr_hash_table_entry) * table->num_entries; |
|
|
|
sizeof(grpc_mdstr_hash_table_entry) * table->size; |
|
|
|
table->entries = gpr_malloc(entry_size); |
|
|
|
table->entries = gpr_malloc(entry_size); |
|
|
|
memset(table->entries, 0, entry_size); |
|
|
|
memset(table->entries, 0, entry_size); |
|
|
|
for (size_t i = 0; i < num_entries; ++i) { |
|
|
|
for (size_t i = 0; i < num_entries; ++i) { |
|
|
@ -98,7 +100,7 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) { |
|
|
|
|
|
|
|
|
|
|
|
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { |
|
|
|
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { |
|
|
|
if (table != NULL && gpr_unref(&table->refs)) { |
|
|
|
if (table != NULL && gpr_unref(&table->refs)) { |
|
|
|
for (size_t i = 0; i < table->num_entries; ++i) { |
|
|
|
for (size_t i = 0; i < table->size; ++i) { |
|
|
|
grpc_mdstr_hash_table_entry* entry = &table->entries[i]; |
|
|
|
grpc_mdstr_hash_table_entry* entry = &table->entries[i]; |
|
|
|
if (entry->key != NULL) { |
|
|
|
if (entry->key != NULL) { |
|
|
|
GRPC_MDSTR_UNREF(entry->key); |
|
|
|
GRPC_MDSTR_UNREF(entry->key); |
|
|
@ -112,11 +114,15 @@ int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t grpc_mdstr_hash_table_num_entries(const grpc_mdstr_hash_table* table) { |
|
|
|
|
|
|
|
return table->num_entries; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, |
|
|
|
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, |
|
|
|
const grpc_mdstr* key) { |
|
|
|
const grpc_mdstr* key) { |
|
|
|
const size_t idx = |
|
|
|
const size_t idx = |
|
|
|
grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */); |
|
|
|
grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */); |
|
|
|
if (idx == table->num_entries) return NULL; // Not found.
|
|
|
|
if (idx == table->size) return NULL; // Not found.
|
|
|
|
return table->entries[idx].value; |
|
|
|
return table->entries[idx].value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -140,3 +146,14 @@ int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void grpc_mdstr_hash_table_iterate( |
|
|
|
|
|
|
|
const grpc_mdstr_hash_table* table, |
|
|
|
|
|
|
|
void (*func)(const grpc_mdstr_hash_table_entry* entry, void* user_data), |
|
|
|
|
|
|
|
void* user_data) { |
|
|
|
|
|
|
|
for (size_t i = 0; i < table->size; ++i) { |
|
|
|
|
|
|
|
if (table->entries[i].key != NULL) { |
|
|
|
|
|
|
|
func(&table->entries[i], user_data); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|