struct int_set_entry * int_set_random_entry(struct int_set *set, int (*predicate)(struct int_set_entry *entry)) { struct int_set_entry *entry; uint32_t i = random() % set->size; if (set->entries == 0) return NULL; for (entry = set->table + i; entry != set->table + set->size; entry++) { if (entry_is_present(entry) && (!predicate || predicate(entry))) { return entry; } } for (entry = set->table; entry != set->table + i; entry++) { if (entry_is_present(entry) && (!predicate || predicate(entry))) { return entry; } } return NULL; }
/** * Inserts the data with the given hash into the table. * * Note that insertion may rearrange the table on a resize or rehash, * so previously found hash_entries are no longer valid after this function. */ int ht_insert(SdbHash *ht, ut32 hash, void *data, SdbListIter *iter) { ut32 hash_address; if (ht->entries >= ht->max_entries) ht_rehash (ht, ht->size_index + 1); else if (ht->deleted_entries + ht->entries >= ht->max_entries) ht_rehash (ht, ht->size_index); hash_address = hash % ht->size; do { SdbHashEntry *entry = ht->table + hash_address; ut32 double_hash; if (!entry_is_present (entry)) { if (entry_is_deleted (entry)) ht->deleted_entries--; entry->hash = hash; entry->data = data; if (!rehash) entry->iter = ls_append (ht->list, data); else entry->iter = iter; ht->entries++; return 1; } double_hash = hash % ht->rehash; if (double_hash == 0) double_hash = 1; hash_address = (hash_address + double_hash) % ht->size; } while (hash_address != hash % ht->size); /* We could hit here if a required resize failed. An unchecked-malloc * application could ignore this result. */ return 0; }
static void int_set_rehash(struct int_set *set, int new_size_index) { struct int_set old_set; struct int_set_entry *table, *entry; if (new_size_index >= ARRAY_SIZE(hash_sizes)) return; table = calloc(hash_sizes[new_size_index].size, sizeof(*set->table)); if (table == NULL) return; old_set = *set; set->table = table; set->size_index = new_size_index; set->size = hash_sizes[set->size_index].size; set->rehash = hash_sizes[set->size_index].rehash; set->max_entries = hash_sizes[set->size_index].max_entries; set->entries = 0; set->deleted_entries = 0; for (entry = old_set.table; entry != old_set.table + old_set.size; entry++) { if (entry_is_present(entry)) { int_set_add(set, entry->value); } } free(old_set.table); }
static void hashtable_rehash(ht_t *ht, unsigned int new_size_index) { ht_t old_ht = *ht; if(new_size_index >= ARRAY_SIZE(hash_sizes)) return; // XXX: This code is redupped! f**k't ht->table = (ht_entry_t *) mem_alloc(hash_sizes[new_size_index].size * (sizeof(*ht->table) + ht->data_length)); if(ht->table == NULL) { return; } ht->data_length = old_ht.data_length; ht->size_index = new_size_index; ht->size = hash_sizes[ht->size_index].size; ht->rehash = hash_sizes[ht->size_index].rehash; ht->max_entries = hash_sizes[ht->size_index].max_entries; ht->entries = 0; ht->deleted_entries = 0; uint32_t element_size = sizeof(*ht->table) + ht->data_length; for (uint32_t idx = 0; idx < old_ht.size; idx++) { ht_entry_t *e = (ht_entry_t *)( (char *) old_ht.table + idx * element_size); if(entry_is_present(e)) { ht_insert2(ht, e->hash, e->data, e->length); } } mem_free(old_ht.table); }
/** * Finds a hash table entry with the given key and hash of that key. * * Returns NULL if no entry is found. Note that the data pointer may be * modified by the user. */ static ht_entry_t* hashtable_search(const ht_t *ht, uint64_t hash) { uint64_t double_hash, hash_address; if(ht == NULL) { return NULL; } uint32_t element_size = sizeof(*ht->table) + ht->data_length; hash_address = hash % ht->size; do { ht_entry_t *entry = (ht_entry_t *)( (char *) ht->table + hash_address * element_size); if(entry_is_free(entry)) { return NULL; } if(entry_is_present(entry) && entry->hash == hash) { return entry; } double_hash = hash % ht->rehash; if(double_hash == 0) { double_hash = 1; } hash_address = (hash_address + double_hash) % ht->size; } while (hash_address != hash % ht->size); return NULL; }
/** * Inserts the given value into the set. * * Note that insertion may rearrange the table on a resize or rehash, * so previously found int_set_entry pointers are no longer valid * after this function. */ struct int_set_entry * int_set_add(struct int_set *set, uint32_t value) { uint32_t hash_address; struct int_set_entry *available_entry = NULL; if (set->entries >= set->max_entries) { int_set_rehash(set, set->size_index + 1); } else if (set->deleted_entries + set->entries >= set->max_entries) { int_set_rehash(set, set->size_index); } hash_address = value % set->size; do { struct int_set_entry *entry = set->table + hash_address; uint32_t double_hash; if (!entry_is_present(entry)) { if (available_entry == NULL) available_entry = entry; if (entry_is_free(entry)) break; if (entry_is_deleted(entry)) { set->deleted_entries--; entry->deleted = 0; } } if (entry->value == value) { return entry; } double_hash = 1 + value % set->rehash; hash_address = (hash_address + double_hash) % set->size; } while (hash_address != value % set->size); if (available_entry) { available_entry->value = value; available_entry->occupied = 1; set->entries++; return available_entry; } /* We could hit here if a required resize failed. An unchecked-malloc * application could ignore this result. */ return NULL; }
int ht_next_key(const ht_t *ht, uint32_t *index, uint64_t *hash) { uint32_t element_size = sizeof(*ht->table) + ht->data_length; for (uint32_t idx = *index; idx < ht->size; idx++) { ht_entry_t *e = (ht_entry_t *)( (char *) ht->table + idx * element_size); if(entry_is_present(e)) { *index = idx + 1; *hash = e->hash; return 0; } } return -1; }
/** * Finds a hash table entry with the given key and hash of that key. * * Returns NULL if no entry is found. Note that the data pointer may be * modified by the user. */ SdbHashEntry* ht_search(SdbHash *ht, ut32 hash) { ut32 double_hash, hash_address = hash % ht->size; if (ht->entries) do { SdbHashEntry *entry = ht->table + hash_address; if (entry_is_free (entry)) return NULL; if (entry_is_present (entry) && entry->hash == hash) return entry; double_hash = hash % ht->rehash; if (double_hash == 0) double_hash = 1; hash_address = (hash_address + double_hash) % ht->size; } while (hash_address != hash % ht->size); return NULL; }
/** * This function is an iterator over the set. * * Pass in NULL for the first entry, as in the start of a for loop. Note that * an iteration over the table is O(table_size) not O(entries). */ struct int_set_entry * int_set_next_entry(struct int_set *set, struct int_set_entry *entry) { if (entry == NULL) entry = set->table; else entry = entry + 1; for (; entry != set->table + set->size; entry++) { if (entry_is_present(entry)) { return entry; } } return NULL; }
/** * Inserts the data with the given hash into the table. * * Note that insertion may rearrange the table on a resize or rehash, * so previously found hash_entries are no longer valid after this function. */ int ht_insert2(ht_t *ht, uint64_t hash, void *data, uint32_t length) { uint64_t hash_address; if(length == 0 || length > ht->data_length) { return -1; } if(ht->entries >= ht->max_entries) { hashtable_rehash(ht, ht->size_index + 1); } else if(ht->deleted_entries + ht->entries >= ht->max_entries) { hashtable_rehash(ht, ht->size_index); } uint32_t element_size = sizeof(*ht->table) + ht->data_length; hash_address = hash % ht->size; do { ht_entry_t *entry = (ht_entry_t *)( (char *) ht->table + hash_address * element_size); if(!entry_is_present(entry)) { if(entry_is_deleted(entry)) { ht->deleted_entries--; } entry->hash = hash; entry->length = length; memcpy(entry->data, data, length); ht->entries++; return 0; } uint64_t double_hash = hash % ht->rehash; if(double_hash == 0) { double_hash = 1; } hash_address = (hash_address + double_hash) % ht->size; } while (hash_address != hash % ht->size); /* We could hit here if a required resize failed. An unchecked-malloc * application could ignore this result. */ return -1; }
/** * Finds a hash table entry with the given key and hash of that key. * * Returns NULL if no entry is found. Note that the data pointer may be * modified by the user. */ static RHTE* ht_(search)(RHT *ht, utH hash) { utH double_hash, hash_address; if (ht == NULL) return NULL; hash_address = hash % ht->size; do { RHTE *entry = ht->table + hash_address; if (entry_is_free (entry)) return NULL; if (entry_is_present (entry) && entry->hash == hash) return entry; double_hash = hash % ht->rehash; if (double_hash == 0) double_hash = 1; hash_address = (hash_address + double_hash) % ht->size; } while (hash_address != hash % ht->size); return NULL; }
static void ht_(rehash)(RHT *ht, int new_size_index) { RHT old_ht = *ht; RHTE *e; if (new_size_index >= ARRAY_SIZE (hash_sizes)) return; // XXX: This code is redupped! f**k't ht->table = calloc (hash_sizes[new_size_index].size, sizeof (*ht->table)); if (!ht->table) return; ht->size_index = new_size_index; ht->size = hash_sizes[ht->size_index].size; ht->rehash = hash_sizes[ht->size_index].rehash; ht->max_entries = hash_sizes[ht->size_index].max_entries; ht->entries = 0; ht->deleted_entries = 0; for (e = old_ht.table; e != old_ht.table + old_ht.size; e++) { if (entry_is_present (e)) ht_(insert) (ht, e->hash, e->data); } free (old_ht.table); }
static void ht_rehash(SdbHash *ht, int new_size_index) { SdbHash old_ht = *ht; SdbHashEntry *e; if (new_size_index >= ARRAY_SIZE (hash_sizes)) return; // XXX: This code is redupped! f**k't ht->table = calloc (hash_sizes[new_size_index].size, sizeof (*ht->table)); if (!ht->table) return; rehash = 1; ht->size_index = new_size_index; ht->size = hash_sizes[ht->size_index].size; ht->rehash = hash_sizes[ht->size_index].rehash; ht->max_entries = hash_sizes[ht->size_index].max_entries; ht->entries = 0; ht->deleted_entries = 0; for (e = old_ht.table; e != old_ht.table + old_ht.size; e++) { if (entry_is_present (e)) ht_insert (ht, e->hash, e->data, e->iter); } free (old_ht.table); rehash = 0; }
/** * Finds a set entry with the given value * * Returns NULL if no entry is found. */ struct int_set_entry * int_set_search(struct int_set *set, uint32_t value) { uint32_t hash_address; hash_address = value % set->size; do { uint32_t double_hash; struct int_set_entry *entry = set->table + hash_address; if (entry_is_free(entry)) { return NULL; } else if (entry_is_present(entry) && entry->value == value) { return entry; } double_hash = 1 + value % set->rehash; hash_address = (hash_address + double_hash) % set->size; } while (hash_address != value % set->size); return NULL; }