diff options
-rw-r--r-- | st.c | 282 |
1 files changed, 162 insertions, 120 deletions
@@ -23,7 +23,7 @@ struct st_table_entry { st_data_t key; st_data_t record; st_table_entry *next; - struct list_node olist; }; typedef struct st_packed_entry { @@ -108,6 +108,8 @@ st_realloc_bins(st_table_entry **bins, st_index_t newsize, st_index_t oldsize) /* Shortcut */ #define bins as.big.bins #define real_entries as.packed.real_entries /* preparation for possible packing improvements */ @@ -193,12 +195,6 @@ stat_col(void) } #endif -static struct list_head * -st_head(const st_table *tbl) -{ - return (struct list_head *)&tbl->as.big.private_list_head; -} - st_table* st_init_table_with_size(const struct st_hash_type *type, st_index_t size) { @@ -224,14 +220,14 @@ st_init_table_with_size(const struct st_hash_type *type, st_index_t size) tbl->entries_packed = size <= MAX_PACKED_HASH; if (tbl->entries_packed) { size = ST_DEFAULT_PACKED_TABLE_SIZE; - tbl->real_entries = 0; } else { size = new_size(size); /* round up to power-of-two */ - list_head_init(st_head(tbl)); } tbl->num_bins = size; tbl->bins = st_alloc_bins(size); return tbl; } @@ -282,6 +278,7 @@ void st_clear(st_table *table) { register st_table_entry *ptr, *next; if (table->entries_packed) { table->num_entries = 0; @@ -289,13 +286,18 @@ st_clear(st_table *table) return; } - list_for_each_safe(st_head(table), ptr, next, olist) { - /* list_del is not needed */ - st_free_entry(ptr); } table->num_entries = 0; - MEMZERO(table->bins, st_table_entry*, table->num_bins); - list_head_init(st_head(table)); } void @@ -463,7 +465,16 @@ add_direct(st_table *table, st_data_t key, st_data_t value, } entry = new_entry(table, key, value, hash_val, bin_pos); - list_add_tail(st_head(table), &entry->olist); table->num_entries++; } @@ -472,7 +483,7 @@ unpack_entries(register st_table *table) { st_index_t i; st_packed_entry packed_bins[MAX_PACKED_HASH]; - register st_table_entry *entry; st_table tmp_table = *table; MEMCPY(packed_bins, PACKED_BINS(table), st_packed_entry, MAX_PACKED_HASH); @@ -484,24 +495,22 @@ unpack_entries(register st_table *table) tmp_table.bins = st_realloc_bins(tmp_table.bins, ST_DEFAULT_INIT_TABLE_SIZE, tmp_table.num_bins); tmp_table.num_bins = ST_DEFAULT_INIT_TABLE_SIZE; #endif - - /* - * order is important here, we need to keep the original table - * walkable during GC (GC may be triggered by new_entry call) - */ i = 0; - list_head_init(st_head(&tmp_table)); do { st_data_t key = packed_bins[i].key; st_data_t val = packed_bins[i].val; st_index_t hash = packed_bins[i].hash; entry = new_entry(&tmp_table, key, val, hash, hash_pos(hash, ST_DEFAULT_INIT_TABLE_SIZE)); - list_add_tail(st_head(&tmp_table), &entry->olist); } while (++i < MAX_PACKED_HASH); *table = tmp_table; - list_head_init(st_head(table)); - list_append_list(st_head(table), st_head(&tmp_table)); } static void @@ -611,10 +620,12 @@ rehash(register st_table *table) table->num_bins = new_num_bins; table->bins = new_bins; - list_for_each(st_head(table), ptr, olist) { - hash_val = hash_pos(ptr->hash, new_num_bins); - ptr->next = new_bins[hash_val]; - new_bins[hash_val] = ptr; } } @@ -622,8 +633,9 @@ st_table* st_copy(st_table *old_table) { st_table *new_table; - st_table_entry *ptr, *entry; st_index_t num_bins = old_table->num_bins; new_table = st_alloc_table(); if (new_table == 0) { @@ -643,12 +655,24 @@ st_copy(st_table *old_table) return new_table; } - list_head_init(st_head(new_table)); - - list_for_each(st_head(old_table), ptr, olist) { - entry = new_entry(new_table, ptr->key, ptr->record, ptr->hash, - hash_pos(ptr->hash, num_bins)); - list_add_tail(st_head(new_table), &entry->olist); } return new_table; @@ -657,7 +681,17 @@ st_copy(st_table *old_table) static inline void remove_entry(st_table *table, st_table_entry *ptr) { - list_del(&ptr->olist); table->num_entries--; } @@ -737,7 +771,6 @@ st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *val int st_shift(register st_table *table, register st_data_t *key, st_data_t *value) { - st_table_entry *old; st_table_entry **prev; register st_table_entry *ptr; @@ -753,13 +786,12 @@ st_shift(register st_table *table, register st_data_t *key, st_data_t *value) return 1; } - old = list_pop(st_head(table), st_table_entry, olist); - table->num_entries--; - prev = &table->bins[hash_pos(old->hash, table->num_bins)]; - while ((ptr = *prev) != old) prev = &ptr->next; *prev = ptr->next; if (value != 0) *value = ptr->record; *key = ptr->key; st_free_entry(ptr); return 1; } @@ -886,8 +918,7 @@ st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data int st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never) { - st_table_entry *ptr, **last, *tmp, *next; - struct list_head *head; enum st_retval retval; st_index_t i; @@ -904,10 +935,8 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t FIND_ENTRY(table, ptr, hash, i); if (retval == ST_CHECK) { if (!ptr) goto deleted; } - if (table->num_entries == 0) return 0; - head = st_head(table); - next = list_entry(ptr->olist.next, st_table_entry, olist); goto unpacked; } switch (retval) { @@ -932,10 +961,14 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t } return 0; } - head = st_head(table); - list_for_each_safe(head, ptr, next, olist) { - if (ptr->key != never) { i = hash_pos(ptr->hash, table->num_bins); retval = (*func)(ptr->key, ptr->record, arg, 0); unpacked: @@ -951,6 +984,8 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t } /* fall through */ case ST_CONTINUE: break; case ST_STOP: return 0; @@ -958,15 +993,16 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t last = &table->bins[hash_pos(ptr->hash, table->num_bins)]; for (; (tmp = *last) != 0; last = &tmp->next) { if (ptr == tmp) { remove_entry(table, ptr); ptr->key = ptr->record = never; ptr->hash = 0; break; } } - if (table->num_entries == 0) return 0; } - } } return 0; } @@ -974,9 +1010,8 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t int st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) { - st_table_entry *ptr, **last, *tmp, *next; enum st_retval retval; - struct list_head *head; st_index_t i; if (table->entries_packed) { @@ -990,8 +1025,6 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) if (!table->entries_packed) { FIND_ENTRY(table, ptr, hash, i); if (!ptr) return 0; - head = st_head(table); - next = list_entry(ptr->olist.next, st_table_entry, olist); goto unpacked; } switch (retval) { @@ -1008,30 +1041,36 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) } return 0; } - head = st_head(table); - list_for_each_safe(head, ptr, next, olist) { - i = hash_pos(ptr->hash, table->num_bins); - retval = (*func)(ptr->key, ptr->record, arg, 0); - unpacked: - switch (retval) { - case ST_CONTINUE: - break; - case ST_CHECK: - case ST_STOP: - return 0; - case ST_DELETE: - last = &table->bins[hash_pos(ptr->hash, table->num_bins)]; - for (; (tmp = *last) != 0; last = &tmp->next) { - if (ptr == tmp) { - *last = ptr->next; - remove_entry(table, ptr); - st_free_entry(ptr); - break; } } - if (table->num_entries == 0) return 0; - } } return 0; } @@ -1053,11 +1092,9 @@ get_keys(st_table *table, st_data_t *keys, st_index_t size, int check, st_data_t } } else { - st_table_entry *ptr; st_data_t *keys_end = keys + size; - - list_for_each(st_head(table), ptr, olist) { - if (keys >= keys_end) break; key = ptr->key; if (check && key == never) continue; *keys++ = key; @@ -1096,11 +1133,9 @@ get_values(st_table *table, st_data_t *values, st_index_t size, int check, st_da } } else { - st_table_entry *ptr; st_data_t *values_end = values + size; - - list_for_each(st_head(table), ptr, olist) { - if (values >= values_end) break; key = ptr->key; if (check && key == never) continue; *values++ = ptr->record; @@ -1126,8 +1161,7 @@ st_values_check(st_table *table, st_data_t *values, st_index_t size, st_data_t n int st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never) { - st_table_entry *ptr, **last, *tmp, *next; - struct list_head *head; enum st_retval retval; st_index_t i; @@ -1145,10 +1179,8 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s FIND_ENTRY(table, ptr, hash, i); if (retval == ST_CHECK) { if (!ptr) goto deleted; } - if (table->num_entries == 0) return 0; - head = st_head(table); - next = list_entry(ptr->olist.next, st_table_entry, olist); goto unpacked; } switch (retval) { @@ -1173,10 +1205,14 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s } return 0; } - head = st_head(table); - list_for_each_rev_safe(head, ptr, next, olist) { - if (ptr->key != never) { i = hash_pos(ptr->hash, table->num_bins); retval = (*func)(ptr->key, ptr->record, arg, 0); unpacked: @@ -1192,6 +1228,8 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s } /* fall through */ case ST_CONTINUE: break; case ST_STOP: return 0; @@ -1199,15 +1237,16 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s last = &table->bins[hash_pos(ptr->hash, table->num_bins)]; for (; (tmp = *last) != 0; last = &tmp->next) { if (ptr == tmp) { remove_entry(table, ptr); ptr->key = ptr->record = never; ptr->hash = 0; break; } } - if (table->num_entries == 0) return 0; } - } } return 0; } @@ -1215,9 +1254,8 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s int st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) { - st_table_entry *ptr, **last, *tmp, *next; enum st_retval retval; - struct list_head *head; st_index_t i; if (table->entries_packed) { @@ -1232,8 +1270,6 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) if (!table->entries_packed) { FIND_ENTRY(table, ptr, hash, i); if (!ptr) return 0; - head = st_head(table); - next = list_entry(ptr->olist.next, st_table_entry, olist); goto unpacked; } switch (retval) { @@ -1249,30 +1285,36 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg) } return 0; } - head = st_head(table); - list_for_each_rev_safe(head, ptr, next, olist) { - i = hash_pos(ptr->hash, table->num_bins); - retval = (*func)(ptr->key, ptr->record, arg, 0); - unpacked: - switch (retval) { - case ST_CONTINUE: - break; - case ST_CHECK: - case ST_STOP: - return 0; - case ST_DELETE: - last = &table->bins[hash_pos(ptr->hash, table->num_bins)]; - for (; (tmp = *last) != 0; last = &tmp->next) { - if (ptr == tmp) { - *last = ptr->next; - remove_entry(table, ptr); - st_free_entry(ptr); - break; } } - if (table->num_entries == 0) return 0; - } } return 0; } |