/** * Insert `key' into the list. * * It is safe to call this routine whilst iterating although there is no * guarantee as to whether the iteration will see the new item. */ void hash_list_insert_sorted(hash_list_t *hl, const void *key, cmp_fn_t func) { link_t *lk; hash_list_check(hl); g_assert(NULL != func); g_assert(!hikset_contains(hl->ht, key)); for (lk = elist_first(&hl->list); lk != NULL; lk = elist_next(lk)) { struct hash_list_item *item = ITEM(lk); if ((*func)(key, item->key) <= 0) break; } if (NULL == lk) { hash_list_append(hl, key); } else { struct hash_list_item *item; WALLOC(item); item->key = key; /* Inserting ``item'' before ``lk'' */ elist_link_insert_before(&hl->list, lk, &item->lnk); hash_list_insert_item(hl, item); } }
/** * Dispose of the data structure, but not of the items it holds. * * @param hl_ptr pointer to the variable containing the address of the list * * As a side effect, the variable containing the address of the list * is nullified, since it is no longer allowed to refer to the structure. */ void hash_list_free(hash_list_t **hl_ptr) { g_assert(NULL != hl_ptr); if (*hl_ptr) { hash_list_t *hl = *hl_ptr; link_t *lk, *next; hash_list_check(hl); if (--hl->refcount != 0) { g_carp("%s: hash list is still referenced! " "(hl=%p, hl->refcount=%d)", G_STRFUNC, cast_to_pointer(hl), hl->refcount); } hikset_free_null(&hl->ht); for (lk = elist_first(&hl->list); lk != NULL; lk = next) { struct hash_list_item *item = ITEM(lk); next = elist_next(lk); /* Embedded, get next before freeing */ WFREE(item); } elist_discard(&hl->list); hl->magic = 0; WFREE(hl); *hl_ptr = NULL; } }
extern int attrlayer_flush(int flags) { static t_elist *curr = &loadedlist; static t_elist *next = NULL; t_attrgroup *attrgroup; unsigned int fcount; unsigned int tcount; fcount = tcount = 0; if (curr == &loadedlist || FLAG_ISSET(flags, FS_ALL)) { curr = elist_next(&loadedlist); next = elist_next(curr); } /* elist_for_each_safe splitted into separate startup for userstep function */ for (; curr != &loadedlist; curr = next, next = elist_next(curr)) { if (!FLAG_ISSET(flags, FS_ALL) && tcount >= prefs_get_user_step()) break; attrgroup = elist_entry(curr, t_attrgroup, loadedlist); switch (attrgroup_flush(attrgroup, flags)) { case 0: /* stop on the first account not flushed (ie accessed too early) */ goto loopout; case 1: fcount++; break; case -1: eventlog(eventlog_level_error, __FUNCTION__, "could not flush account"); break; default: break; } tcount++; } loopout: if (fcount > 0) eventlog(eventlog_level_debug, __FUNCTION__, "flushed %u user accounts", fcount); if (!FLAG_ISSET(flags, FS_ALL) && curr != &loadedlist) return 1; return 0; }
/** * Get the next item after a given key. * * This is more costly than taking an iterator and traversing the structure, * but it is safe to use when the processing of each item can remove the item * from the traversed structure. * * Here's template code demonstrating usage: * * void *next = hash_list_head(hl); * while (next) { * struct <item> *item = next; * next = hash_list_next(hl, next); * <process item, can be safely removed from hl> * } * * @return pointer to next item, NULL if we reached the end of the list. */ void * hash_list_next(hash_list_t *hl, const void *key) { struct hash_list_item *item; hash_list_check(hl); item = hikset_lookup(hl->ht, key); item = item ? elist_data(&hl->list, elist_next(&item->lnk)) : NULL; return item ? deconstify_pointer(item->key) : NULL; }
/** * Apply `func' to all the items in the structure. */ void hash_list_foreach(const hash_list_t *hl, data_fn_t func, void *user_data) { link_t *lk; hash_list_check(hl); g_assert(NULL != func); for (lk = elist_first(&hl->list); lk != NULL; lk = elist_next(lk)) { struct hash_list_item *item = ITEM(lk); (*func)(deconstify_pointer(item->key), user_data); } hash_list_regression(hl); }
/** * Get the previous data item from the iterator, or NULL if none. */ G_GNUC_HOT void * hash_list_iter_previous(hash_list_iter_t *iter) { link_t *prev; hash_list_iter_check(iter); prev = iter->prev; if (prev != NULL) { iter->item = ITEM(prev); iter->next = elist_next(prev); iter->prev = elist_prev(prev); return deconstify_pointer(iter->item->key); } else { return NULL; } }
/** * Get the next data item from the iterator, or NULL if none. */ G_GNUC_HOT void * hash_list_iter_next(hash_list_iter_t *iter) { link_t *next; hash_list_iter_check(iter); next = iter->next; if (next != NULL) { iter->item = ITEM(next); iter->prev = elist_prev(next); iter->next = elist_next(next); return deconstify_pointer(iter->item->key); } else { return NULL; } }
/** * Apply `func' to all the items in the structure, removing the entry * if `func' returns TRUE. * * @return the amount of entries removed from the list. */ size_t hash_list_foreach_remove(hash_list_t *hl, data_rm_fn_t func, void *data) { link_t *lk, *next; size_t removed = 0; hash_list_check(hl); g_assert(func != NULL); for (lk = elist_first(&hl->list); lk != NULL; lk = next) { struct hash_list_item *item = ITEM(lk); next = elist_next(lk); if ((*func)(deconstify_pointer(item->key), data)) { hash_list_remove_item(hl, item); removed++; } } hash_list_regression(hl); return removed; }
/** * Get an iterator on the list, positionned at the specified item. * Get next items with hash_list_iter_next() or hash_list_iter_previous(). * * @return the iterator object or NULL if the key is not in the list. */ hash_list_iter_t * hash_list_iterator_at(hash_list_t *hl, const void *key) { if (hl) { struct hash_list_item *item; hash_list_check(hl); item = hikset_lookup(hl->ht, key); if (item) { hash_list_iter_t *iter; iter = hash_list_iterator_new(hl, HASH_LIST_ITER_UNDEFINED); iter->prev = elist_prev(&item->lnk); iter->next = elist_next(&item->lnk); iter->item = item; return iter; } else { return NULL; } } else { return NULL; } }