mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
st.c: use ccan linked-list (try 2)
This improves the bm_vm2_bighash benchmark significantly by removing branches during insert, but slows down anything requiring iteration with the more complex loop termination checking. Speedup ratio of 1.10 - 1.20 is typical for the vm2_bighash benchmark. * include/ruby/st.h (struct st_table): hide struct list_head * st.c (struct st_table_entry): adjust struct (head, tail): remove shortcut macros (st_head): new wrapper function (st_init_table_with_size): adjust to new struct and API (st_clear): ditto (add_direct): ditto (unpack_entries): ditto (rehash): ditto (st_copy): ditto (remove_entry): ditto (st_shift): ditto (st_foreach_check): ditto (st_foreach): ditto (get_keys): ditto (get_values): ditto (st_values_check): ditto (st_reverse_foreach_check): ditto (unused) (st_reverse_foreach): ditto (unused) [ruby-core:69726] [Misc #10278] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51044 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
08414a6afa
commit
d3725a86de
3 changed files with 144 additions and 163 deletions
23
ChangeLog
23
ChangeLog
|
@ -1,3 +1,26 @@
|
||||||
|
Sat Jun 27 06:58:01 2015 Eric Wong <e@80x24.org>
|
||||||
|
|
||||||
|
* include/ruby/st.h (struct st_table): hide struct list_head
|
||||||
|
* st.c (struct st_table_entry): adjust struct
|
||||||
|
(head, tail): remove shortcut macros
|
||||||
|
(st_head): new wrapper function
|
||||||
|
(st_init_table_with_size): adjust to new struct and API
|
||||||
|
(st_clear): ditto
|
||||||
|
(add_direct): ditto
|
||||||
|
(unpack_entries): ditto
|
||||||
|
(rehash): ditto
|
||||||
|
(st_copy): ditto
|
||||||
|
(remove_entry): ditto
|
||||||
|
(st_shift): ditto
|
||||||
|
(st_foreach_check): ditto
|
||||||
|
(st_foreach): ditto
|
||||||
|
(get_keys): ditto
|
||||||
|
(get_values): ditto
|
||||||
|
(st_values_check): ditto
|
||||||
|
(st_reverse_foreach_check): ditto (unused)
|
||||||
|
(st_reverse_foreach): ditto (unused)
|
||||||
|
[ruby-core:69726] [Misc #10278]
|
||||||
|
|
||||||
Fri Jun 26 12:48:37 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Jun 26 12:48:37 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* transcode.c (load_transcoder_entry): fix transcoder loading race
|
* transcode.c (load_transcoder_entry): fix transcoder loading race
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct st_table {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
struct st_table_entry **bins;
|
struct st_table_entry **bins;
|
||||||
struct st_table_entry *head, *tail;
|
void *private_list_head[2];
|
||||||
} big;
|
} big;
|
||||||
struct {
|
struct {
|
||||||
struct st_packed_entry *entries;
|
struct st_packed_entry *entries;
|
||||||
|
|
282
st.c
282
st.c
|
@ -23,7 +23,7 @@ struct st_table_entry {
|
||||||
st_data_t key;
|
st_data_t key;
|
||||||
st_data_t record;
|
st_data_t record;
|
||||||
st_table_entry *next;
|
st_table_entry *next;
|
||||||
st_table_entry *fore, *back;
|
struct list_node olist;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct st_packed_entry {
|
typedef struct st_packed_entry {
|
||||||
|
@ -108,8 +108,6 @@ st_realloc_bins(st_table_entry **bins, st_index_t newsize, st_index_t oldsize)
|
||||||
|
|
||||||
/* Shortcut */
|
/* Shortcut */
|
||||||
#define bins as.big.bins
|
#define bins as.big.bins
|
||||||
#define head as.big.head
|
|
||||||
#define tail as.big.tail
|
|
||||||
#define real_entries as.packed.real_entries
|
#define real_entries as.packed.real_entries
|
||||||
|
|
||||||
/* preparation for possible packing improvements */
|
/* preparation for possible packing improvements */
|
||||||
|
@ -195,6 +193,12 @@ stat_col(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static struct list_head *
|
||||||
|
st_head(const st_table *tbl)
|
||||||
|
{
|
||||||
|
return (struct list_head *)&tbl->as.big.private_list_head;
|
||||||
|
}
|
||||||
|
|
||||||
st_table*
|
st_table*
|
||||||
st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
|
st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
|
||||||
{
|
{
|
||||||
|
@ -220,14 +224,14 @@ st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
|
||||||
tbl->entries_packed = size <= MAX_PACKED_HASH;
|
tbl->entries_packed = size <= MAX_PACKED_HASH;
|
||||||
if (tbl->entries_packed) {
|
if (tbl->entries_packed) {
|
||||||
size = ST_DEFAULT_PACKED_TABLE_SIZE;
|
size = ST_DEFAULT_PACKED_TABLE_SIZE;
|
||||||
|
tbl->real_entries = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
size = new_size(size); /* round up to power-of-two */
|
size = new_size(size); /* round up to power-of-two */
|
||||||
|
list_head_init(st_head(tbl));
|
||||||
}
|
}
|
||||||
tbl->num_bins = size;
|
tbl->num_bins = size;
|
||||||
tbl->bins = st_alloc_bins(size);
|
tbl->bins = st_alloc_bins(size);
|
||||||
tbl->head = 0;
|
|
||||||
tbl->tail = 0;
|
|
||||||
|
|
||||||
return tbl;
|
return tbl;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +282,6 @@ void
|
||||||
st_clear(st_table *table)
|
st_clear(st_table *table)
|
||||||
{
|
{
|
||||||
register st_table_entry *ptr, *next;
|
register st_table_entry *ptr, *next;
|
||||||
st_index_t i;
|
|
||||||
|
|
||||||
if (table->entries_packed) {
|
if (table->entries_packed) {
|
||||||
table->num_entries = 0;
|
table->num_entries = 0;
|
||||||
|
@ -286,18 +289,13 @@ st_clear(st_table *table)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < table->num_bins; i++) {
|
list_for_each_safe(st_head(table), ptr, next, olist) {
|
||||||
ptr = table->bins[i];
|
/* list_del is not needed */
|
||||||
table->bins[i] = 0;
|
st_free_entry(ptr);
|
||||||
while (ptr != 0) {
|
|
||||||
next = ptr->next;
|
|
||||||
st_free_entry(ptr);
|
|
||||||
ptr = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
table->num_entries = 0;
|
table->num_entries = 0;
|
||||||
table->head = 0;
|
MEMZERO(table->bins, st_table_entry*, table->num_bins);
|
||||||
table->tail = 0;
|
list_head_init(st_head(table));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -465,16 +463,7 @@ add_direct(st_table *table, st_data_t key, st_data_t value,
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = new_entry(table, key, value, hash_val, bin_pos);
|
entry = new_entry(table, key, value, hash_val, bin_pos);
|
||||||
|
list_add_tail(st_head(table), &entry->olist);
|
||||||
if (table->head != 0) {
|
|
||||||
entry->fore = 0;
|
|
||||||
(entry->back = table->tail)->fore = entry;
|
|
||||||
table->tail = entry;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
table->head = table->tail = entry;
|
|
||||||
entry->fore = entry->back = 0;
|
|
||||||
}
|
|
||||||
table->num_entries++;
|
table->num_entries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,7 +472,7 @@ unpack_entries(register st_table *table)
|
||||||
{
|
{
|
||||||
st_index_t i;
|
st_index_t i;
|
||||||
st_packed_entry packed_bins[MAX_PACKED_HASH];
|
st_packed_entry packed_bins[MAX_PACKED_HASH];
|
||||||
register st_table_entry *entry, *preventry = 0, **chain;
|
register st_table_entry *entry;
|
||||||
st_table tmp_table = *table;
|
st_table tmp_table = *table;
|
||||||
|
|
||||||
MEMCPY(packed_bins, PACKED_BINS(table), st_packed_entry, MAX_PACKED_HASH);
|
MEMCPY(packed_bins, PACKED_BINS(table), st_packed_entry, MAX_PACKED_HASH);
|
||||||
|
@ -495,22 +484,24 @@ 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.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;
|
tmp_table.num_bins = ST_DEFAULT_INIT_TABLE_SIZE;
|
||||||
#endif
|
#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;
|
i = 0;
|
||||||
chain = &tmp_table.head;
|
list_head_init(st_head(&tmp_table));
|
||||||
do {
|
do {
|
||||||
st_data_t key = packed_bins[i].key;
|
st_data_t key = packed_bins[i].key;
|
||||||
st_data_t val = packed_bins[i].val;
|
st_data_t val = packed_bins[i].val;
|
||||||
st_index_t hash = packed_bins[i].hash;
|
st_index_t hash = packed_bins[i].hash;
|
||||||
entry = new_entry(&tmp_table, key, val, hash,
|
entry = new_entry(&tmp_table, key, val, hash,
|
||||||
hash_pos(hash, ST_DEFAULT_INIT_TABLE_SIZE));
|
hash_pos(hash, ST_DEFAULT_INIT_TABLE_SIZE));
|
||||||
*chain = entry;
|
list_add_tail(st_head(&tmp_table), &entry->olist);
|
||||||
entry->back = preventry;
|
|
||||||
preventry = entry;
|
|
||||||
chain = &entry->fore;
|
|
||||||
} while (++i < MAX_PACKED_HASH);
|
} while (++i < MAX_PACKED_HASH);
|
||||||
*chain = NULL;
|
|
||||||
tmp_table.tail = entry;
|
|
||||||
*table = tmp_table;
|
*table = tmp_table;
|
||||||
|
list_head_init(st_head(table));
|
||||||
|
list_append_list(st_head(table), st_head(&tmp_table));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -620,12 +611,10 @@ rehash(register st_table *table)
|
||||||
table->num_bins = new_num_bins;
|
table->num_bins = new_num_bins;
|
||||||
table->bins = new_bins;
|
table->bins = new_bins;
|
||||||
|
|
||||||
if ((ptr = table->head) != 0) {
|
list_for_each(st_head(table), ptr, olist) {
|
||||||
do {
|
hash_val = hash_pos(ptr->hash, new_num_bins);
|
||||||
hash_val = hash_pos(ptr->hash, new_num_bins);
|
ptr->next = new_bins[hash_val];
|
||||||
ptr->next = new_bins[hash_val];
|
new_bins[hash_val] = ptr;
|
||||||
new_bins[hash_val] = ptr;
|
|
||||||
} while ((ptr = ptr->fore) != 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,9 +622,8 @@ st_table*
|
||||||
st_copy(st_table *old_table)
|
st_copy(st_table *old_table)
|
||||||
{
|
{
|
||||||
st_table *new_table;
|
st_table *new_table;
|
||||||
st_table_entry *ptr, *entry, *prev, **tailp;
|
st_table_entry *ptr, *entry;
|
||||||
st_index_t num_bins = old_table->num_bins;
|
st_index_t num_bins = old_table->num_bins;
|
||||||
st_index_t hash_val;
|
|
||||||
|
|
||||||
new_table = st_alloc_table();
|
new_table = st_alloc_table();
|
||||||
if (new_table == 0) {
|
if (new_table == 0) {
|
||||||
|
@ -655,24 +643,12 @@ st_copy(st_table *old_table)
|
||||||
return new_table;
|
return new_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ptr = old_table->head) != 0) {
|
list_head_init(st_head(new_table));
|
||||||
prev = 0;
|
|
||||||
tailp = &new_table->head;
|
list_for_each(st_head(old_table), ptr, olist) {
|
||||||
do {
|
entry = new_entry(new_table, ptr->key, ptr->record, ptr->hash,
|
||||||
entry = st_alloc_entry();
|
hash_pos(ptr->hash, num_bins));
|
||||||
if (entry == 0) {
|
list_add_tail(st_head(new_table), &entry->olist);
|
||||||
st_free_table(new_table);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*entry = *ptr;
|
|
||||||
hash_val = hash_pos(entry->hash, num_bins);
|
|
||||||
entry->next = new_table->bins[hash_val];
|
|
||||||
new_table->bins[hash_val] = entry;
|
|
||||||
entry->back = prev;
|
|
||||||
*tailp = prev = entry;
|
|
||||||
tailp = &entry->fore;
|
|
||||||
} while ((ptr = ptr->fore) != 0);
|
|
||||||
new_table->tail = prev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_table;
|
return new_table;
|
||||||
|
@ -681,17 +657,7 @@ st_copy(st_table *old_table)
|
||||||
static inline void
|
static inline void
|
||||||
remove_entry(st_table *table, st_table_entry *ptr)
|
remove_entry(st_table *table, st_table_entry *ptr)
|
||||||
{
|
{
|
||||||
if (ptr->fore == 0 && ptr->back == 0) {
|
list_del(&ptr->olist);
|
||||||
table->head = 0;
|
|
||||||
table->tail = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
st_table_entry *fore = ptr->fore, *back = ptr->back;
|
|
||||||
if (fore) fore->back = back;
|
|
||||||
if (back) back->fore = fore;
|
|
||||||
if (ptr == table->head) table->head = fore;
|
|
||||||
if (ptr == table->tail) table->tail = back;
|
|
||||||
}
|
|
||||||
table->num_entries--;
|
table->num_entries--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,6 +737,7 @@ st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *val
|
||||||
int
|
int
|
||||||
st_shift(register st_table *table, register st_data_t *key, st_data_t *value)
|
st_shift(register st_table *table, register st_data_t *key, st_data_t *value)
|
||||||
{
|
{
|
||||||
|
st_table_entry *old;
|
||||||
st_table_entry **prev;
|
st_table_entry **prev;
|
||||||
register st_table_entry *ptr;
|
register st_table_entry *ptr;
|
||||||
|
|
||||||
|
@ -786,12 +753,13 @@ st_shift(register st_table *table, register st_data_t *key, st_data_t *value)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = &table->bins[hash_pos(table->head->hash, table->num_bins)];
|
old = list_pop(st_head(table), st_table_entry, olist);
|
||||||
while ((ptr = *prev) != table->head) prev = &ptr->next;
|
table->num_entries--;
|
||||||
|
prev = &table->bins[hash_pos(old->hash, table->num_bins)];
|
||||||
|
while ((ptr = *prev) != old) prev = &ptr->next;
|
||||||
*prev = ptr->next;
|
*prev = ptr->next;
|
||||||
if (value != 0) *value = ptr->record;
|
if (value != 0) *value = ptr->record;
|
||||||
*key = ptr->key;
|
*key = ptr->key;
|
||||||
remove_entry(table, ptr);
|
|
||||||
st_free_entry(ptr);
|
st_free_entry(ptr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -918,7 +886,8 @@ st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data
|
||||||
int
|
int
|
||||||
st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
|
st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
|
||||||
{
|
{
|
||||||
st_table_entry *ptr, **last, *tmp;
|
st_table_entry *ptr, **last, *tmp, *next;
|
||||||
|
struct list_head *head;
|
||||||
enum st_retval retval;
|
enum st_retval retval;
|
||||||
st_index_t i;
|
st_index_t i;
|
||||||
|
|
||||||
|
@ -935,8 +904,10 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t
|
||||||
FIND_ENTRY(table, ptr, hash, i);
|
FIND_ENTRY(table, ptr, hash, i);
|
||||||
if (retval == ST_CHECK) {
|
if (retval == ST_CHECK) {
|
||||||
if (!ptr) goto deleted;
|
if (!ptr) goto deleted;
|
||||||
goto unpacked_continue;
|
|
||||||
}
|
}
|
||||||
|
if (table->num_entries == 0) return 0;
|
||||||
|
head = st_head(table);
|
||||||
|
next = list_entry(ptr->olist.next, st_table_entry, olist);
|
||||||
goto unpacked;
|
goto unpacked;
|
||||||
}
|
}
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
@ -961,14 +932,10 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ptr = table->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr != 0) {
|
head = st_head(table);
|
||||||
do {
|
list_for_each_safe(head, ptr, next, olist) {
|
||||||
if (ptr->key == never)
|
if (ptr->key != never) {
|
||||||
goto unpacked_continue;
|
|
||||||
i = hash_pos(ptr->hash, table->num_bins);
|
i = hash_pos(ptr->hash, table->num_bins);
|
||||||
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
||||||
unpacked:
|
unpacked:
|
||||||
|
@ -984,8 +951,6 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case ST_CONTINUE:
|
case ST_CONTINUE:
|
||||||
unpacked_continue:
|
|
||||||
ptr = ptr->fore;
|
|
||||||
break;
|
break;
|
||||||
case ST_STOP:
|
case ST_STOP:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -993,16 +958,15 @@ 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)];
|
last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
|
||||||
for (; (tmp = *last) != 0; last = &tmp->next) {
|
for (; (tmp = *last) != 0; last = &tmp->next) {
|
||||||
if (ptr == tmp) {
|
if (ptr == tmp) {
|
||||||
tmp = ptr->fore;
|
|
||||||
remove_entry(table, ptr);
|
remove_entry(table, ptr);
|
||||||
ptr->key = ptr->record = never;
|
ptr->key = ptr->record = never;
|
||||||
ptr->hash = 0;
|
ptr->hash = 0;
|
||||||
ptr = tmp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (table->num_entries == 0) return 0;
|
||||||
}
|
}
|
||||||
} while (ptr && table->head);
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1010,8 +974,9 @@ st_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t
|
||||||
int
|
int
|
||||||
st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
||||||
{
|
{
|
||||||
st_table_entry *ptr, **last, *tmp;
|
st_table_entry *ptr, **last, *tmp, *next;
|
||||||
enum st_retval retval;
|
enum st_retval retval;
|
||||||
|
struct list_head *head;
|
||||||
st_index_t i;
|
st_index_t i;
|
||||||
|
|
||||||
if (table->entries_packed) {
|
if (table->entries_packed) {
|
||||||
|
@ -1025,6 +990,8 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
||||||
if (!table->entries_packed) {
|
if (!table->entries_packed) {
|
||||||
FIND_ENTRY(table, ptr, hash, i);
|
FIND_ENTRY(table, ptr, hash, i);
|
||||||
if (!ptr) return 0;
|
if (!ptr) return 0;
|
||||||
|
head = st_head(table);
|
||||||
|
next = list_entry(ptr->olist.next, st_table_entry, olist);
|
||||||
goto unpacked;
|
goto unpacked;
|
||||||
}
|
}
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
@ -1041,36 +1008,30 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ptr = table->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr != 0) {
|
head = st_head(table);
|
||||||
do {
|
list_for_each_safe(head, ptr, next, olist) {
|
||||||
i = hash_pos(ptr->hash, table->num_bins);
|
i = hash_pos(ptr->hash, table->num_bins);
|
||||||
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
||||||
unpacked:
|
unpacked:
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
case ST_CONTINUE:
|
case ST_CONTINUE:
|
||||||
ptr = ptr->fore;
|
break;
|
||||||
break;
|
case ST_CHECK:
|
||||||
case ST_CHECK:
|
case ST_STOP:
|
||||||
case ST_STOP:
|
return 0;
|
||||||
return 0;
|
case ST_DELETE:
|
||||||
case ST_DELETE:
|
last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
|
||||||
last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
|
for (; (tmp = *last) != 0; last = &tmp->next) {
|
||||||
for (; (tmp = *last) != 0; last = &tmp->next) {
|
if (ptr == tmp) {
|
||||||
if (ptr == tmp) {
|
*last = ptr->next;
|
||||||
tmp = ptr->fore;
|
remove_entry(table, ptr);
|
||||||
*last = ptr->next;
|
st_free_entry(ptr);
|
||||||
remove_entry(table, ptr);
|
break;
|
||||||
st_free_entry(ptr);
|
|
||||||
ptr = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (ptr && table->head);
|
if (table->num_entries == 0) return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1092,9 +1053,11 @@ get_keys(st_table *table, st_data_t *keys, st_index_t size, int check, st_data_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
st_table_entry *ptr = table->head;
|
st_table_entry *ptr;
|
||||||
st_data_t *keys_end = keys + size;
|
st_data_t *keys_end = keys + size;
|
||||||
for (; ptr && keys < keys_end; ptr = ptr->fore) {
|
|
||||||
|
list_for_each(st_head(table), ptr, olist) {
|
||||||
|
if (keys >= keys_end) break;
|
||||||
key = ptr->key;
|
key = ptr->key;
|
||||||
if (check && key == never) continue;
|
if (check && key == never) continue;
|
||||||
*keys++ = key;
|
*keys++ = key;
|
||||||
|
@ -1133,9 +1096,11 @@ get_values(st_table *table, st_data_t *values, st_index_t size, int check, st_da
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
st_table_entry *ptr = table->head;
|
st_table_entry *ptr;
|
||||||
st_data_t *values_end = values + size;
|
st_data_t *values_end = values + size;
|
||||||
for (; ptr && values < values_end; ptr = ptr->fore) {
|
|
||||||
|
list_for_each(st_head(table), ptr, olist) {
|
||||||
|
if (values >= values_end) break;
|
||||||
key = ptr->key;
|
key = ptr->key;
|
||||||
if (check && key == never) continue;
|
if (check && key == never) continue;
|
||||||
*values++ = ptr->record;
|
*values++ = ptr->record;
|
||||||
|
@ -1161,7 +1126,8 @@ st_values_check(st_table *table, st_data_t *values, st_index_t size, st_data_t n
|
||||||
int
|
int
|
||||||
st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
|
st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
|
||||||
{
|
{
|
||||||
st_table_entry *ptr, **last, *tmp;
|
st_table_entry *ptr, **last, *tmp, *next;
|
||||||
|
struct list_head *head;
|
||||||
enum st_retval retval;
|
enum st_retval retval;
|
||||||
st_index_t i;
|
st_index_t i;
|
||||||
|
|
||||||
|
@ -1179,8 +1145,10 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s
|
||||||
FIND_ENTRY(table, ptr, hash, i);
|
FIND_ENTRY(table, ptr, hash, i);
|
||||||
if (retval == ST_CHECK) {
|
if (retval == ST_CHECK) {
|
||||||
if (!ptr) goto deleted;
|
if (!ptr) goto deleted;
|
||||||
goto unpacked_continue;
|
|
||||||
}
|
}
|
||||||
|
if (table->num_entries == 0) return 0;
|
||||||
|
head = st_head(table);
|
||||||
|
next = list_entry(ptr->olist.next, st_table_entry, olist);
|
||||||
goto unpacked;
|
goto unpacked;
|
||||||
}
|
}
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
@ -1205,14 +1173,10 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ptr = table->tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr != 0) {
|
head = st_head(table);
|
||||||
do {
|
list_for_each_rev_safe(head, ptr, next, olist) {
|
||||||
if (ptr->key == never)
|
if (ptr->key != never) {
|
||||||
goto unpacked_continue;
|
|
||||||
i = hash_pos(ptr->hash, table->num_bins);
|
i = hash_pos(ptr->hash, table->num_bins);
|
||||||
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
||||||
unpacked:
|
unpacked:
|
||||||
|
@ -1228,8 +1192,6 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case ST_CONTINUE:
|
case ST_CONTINUE:
|
||||||
unpacked_continue:
|
|
||||||
ptr = ptr->back;
|
|
||||||
break;
|
break;
|
||||||
case ST_STOP:
|
case ST_STOP:
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1237,16 +1199,15 @@ 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)];
|
last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
|
||||||
for (; (tmp = *last) != 0; last = &tmp->next) {
|
for (; (tmp = *last) != 0; last = &tmp->next) {
|
||||||
if (ptr == tmp) {
|
if (ptr == tmp) {
|
||||||
tmp = ptr->back;
|
|
||||||
remove_entry(table, ptr);
|
remove_entry(table, ptr);
|
||||||
ptr->key = ptr->record = never;
|
ptr->key = ptr->record = never;
|
||||||
ptr->hash = 0;
|
ptr->hash = 0;
|
||||||
ptr = tmp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (table->num_entries == 0) return 0;
|
||||||
}
|
}
|
||||||
} while (ptr && table->head);
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1254,8 +1215,9 @@ st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, s
|
||||||
int
|
int
|
||||||
st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
||||||
{
|
{
|
||||||
st_table_entry *ptr, **last, *tmp;
|
st_table_entry *ptr, **last, *tmp, *next;
|
||||||
enum st_retval retval;
|
enum st_retval retval;
|
||||||
|
struct list_head *head;
|
||||||
st_index_t i;
|
st_index_t i;
|
||||||
|
|
||||||
if (table->entries_packed) {
|
if (table->entries_packed) {
|
||||||
|
@ -1270,6 +1232,8 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
||||||
if (!table->entries_packed) {
|
if (!table->entries_packed) {
|
||||||
FIND_ENTRY(table, ptr, hash, i);
|
FIND_ENTRY(table, ptr, hash, i);
|
||||||
if (!ptr) return 0;
|
if (!ptr) return 0;
|
||||||
|
head = st_head(table);
|
||||||
|
next = list_entry(ptr->olist.next, st_table_entry, olist);
|
||||||
goto unpacked;
|
goto unpacked;
|
||||||
}
|
}
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
|
@ -1285,36 +1249,30 @@ st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ptr = table->tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr != 0) {
|
head = st_head(table);
|
||||||
do {
|
list_for_each_rev_safe(head, ptr, next, olist) {
|
||||||
i = hash_pos(ptr->hash, table->num_bins);
|
i = hash_pos(ptr->hash, table->num_bins);
|
||||||
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
retval = (*func)(ptr->key, ptr->record, arg, 0);
|
||||||
unpacked:
|
unpacked:
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
case ST_CONTINUE:
|
case ST_CONTINUE:
|
||||||
ptr = ptr->back;
|
break;
|
||||||
break;
|
case ST_CHECK:
|
||||||
case ST_CHECK:
|
case ST_STOP:
|
||||||
case ST_STOP:
|
return 0;
|
||||||
return 0;
|
case ST_DELETE:
|
||||||
case ST_DELETE:
|
last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
|
||||||
last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
|
for (; (tmp = *last) != 0; last = &tmp->next) {
|
||||||
for (; (tmp = *last) != 0; last = &tmp->next) {
|
if (ptr == tmp) {
|
||||||
if (ptr == tmp) {
|
*last = ptr->next;
|
||||||
tmp = ptr->back;
|
remove_entry(table, ptr);
|
||||||
*last = ptr->next;
|
st_free_entry(ptr);
|
||||||
remove_entry(table, ptr);
|
break;
|
||||||
st_free_entry(ptr);
|
|
||||||
ptr = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (ptr && table->head);
|
if (table->num_entries == 0) return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue