From f27d1a4c460087eaf953e7ac9466bb97de184563 Mon Sep 17 00:00:00 2001 From: Egor Date: Mon, 23 Oct 2023 12:58:31 +0300 Subject: [PATCH] the great findfirst refactoring not only is the syntax markedly better now, but also it's no longer nescessary to allocate any memory to do a traversal. --- src/irc.c | 263 ++++++++++++++++++----------------------------- src/main.c | 10 +- src/map.h | 99 ++++++++---------- src/map_dynarr.c | 35 ++----- src/map_trie.c | 88 ++++++++-------- src/net.c | 15 +-- 6 files changed, 200 insertions(+), 310 deletions(-) diff --git a/src/irc.c b/src/irc.c index 559bcef..8fa0ecb 100644 --- a/src/irc.c +++ b/src/irc.c @@ -28,33 +28,27 @@ void chanlog() { } } void sendbuf_chan_caps(struct channel *chan, unsigned positive, unsigned negative) { - map_find_t f = {0}; - if (map_findfirst(&f, &chan->members) == 1) - do { - struct client_data *cl = f->value; - if (!(~cl->caps & positive) && !(cl->caps & negative)) - sendbuf(cl); - } while (map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&chan->members, 0, &cl) + if (!(~cl->caps & positive) && !(cl->caps & negative)) + sendbuf(cl); } void sendbuf_chan(struct channel *chan) { sendbuf_chan_caps(chan, 0, 0); } void sendbuf_list_sans_self_caps(struct client_data *client, map_t *ls, int cookie, int positive, int negative) { - map_find_t f = {0}; - if (map_findfirst(&f, ls) == 1) - do { - struct client_data *cl = f->value; - if (client != cl) { - if (cookie) { - if (cookie != cl->cookie) - cl->cookie = cookie; - else - continue; - } - if (!(~cl->caps & positive) && !(cl->caps & negative)) - sendbuf(cl); + struct client_data *cl; + map_foreach(ls, 0, &cl) + if (client != cl) { + if (cookie) { + if (cookie != cl->cookie) + cl->cookie = cookie; + else + continue; } - } while (map_findnext(&f) == 1); + if (!(~cl->caps & positive) && !(cl->caps & negative)) + sendbuf(cl); + } } void sendbuf_list_sans_self(struct client_data *client, map_t *ls, int cookie) { sendbuf_list_sans_self_caps(client, ls, cookie, 0, 0); @@ -63,24 +57,18 @@ int get_cookie() { static int cookie = 0; if (++cookie == 0) { // handle overflow - map_find_t f = {0}; - if (map_findfirst(&f, &client_map) == 1) - do { - struct client_data *cl = f->value; - cl->cookie = 0; - } while (map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&client_map, 0, &cl) + cl->cookie = 0; cookie++; } return cookie; } void sendbuf_visible_caps(struct client_data *client, int positive, int negative) { int cookie = get_cookie(); - map_find_t f = {0}; - if (map_findfirst(&f, &client->channels) == 1) - do { - struct channel *chan = f->value; - sendbuf_list_sans_self_caps(client, &chan->members, cookie, positive, negative); - } while (map_findnext(&f) == 1); + struct channel *chan; + map_foreach(&client->channels, 0, &chan) + sendbuf_list_sans_self_caps(client, &chan->members, cookie, positive, negative); } void sendbuf_visible(struct client_data *client) { sendbuf_visible_caps(client, 0, 0); @@ -100,14 +88,10 @@ const char *format_umodes(struct client_data *cl) { } int match_list(struct client_data *cl, map_t *list) { - map_find_t f = {0}; - if (map_findfirst(&f, list) == 1) - do { - if (irc_glob(cl->nuh, f->key)) { - map_findfree(&f); - return 1; - } - } while (map_findnext(&f) == 1); + const char *key; + map_foreach(list, &key, 0) + if (irc_glob(cl->nuh, key)) + return 1; return 0; } int parsePacket(struct client_data *client) { @@ -365,13 +349,10 @@ int processPacket(struct client_data *client, char *source, char *command, int a if (!(client->umode & UMODE_OPER)) return err_noprivileges(client), sendbuf(client), 0; msg_wallops(client, args[0]); - map_find_t f = {0}; - if (map_findfirst(&f, &client_map) == 1) - do { - struct client_data *cl = f->value; - if (cl->umode & UMODE_WALLOPS) - sendbuf(cl); - } while (map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&client_map, 0, &cl) + if (cl->umode & UMODE_WALLOPS) + sendbuf(cl); } else if(strcmp(command, "KILL") == 0) { if (!is_registered(client)) return err_notregistered(client), sendbuf(client), 0; @@ -385,13 +366,10 @@ int processPacket(struct client_data *client, char *source, char *command, int a if (client == cl) return 0; // FIXME: error message msg_kill(client, cl, args[1] ? args[1] : "(no reason)"); - map_find_t f = {0}; - if (map_findfirst(&f, &client_map) == 1) - do { - struct client_data *cl2 = f->value; - if (cl2->umode & UMODE_OPER) - sendbuf(cl2); - } while (map_findnext(&f) == 1); + struct client_data *cl2; + map_foreach(&client_map, 0, &cl2) + if (cl2->umode & UMODE_OPER) + sendbuf(cl2); // FIXME: add appropraite QUIT message killConnection(cl, 0); } else if(strcmp(command, "JEDGAR") == 0) { @@ -416,12 +394,8 @@ int processPacket(struct client_data *client, char *source, char *command, int a if (!args[0]) return err_needmoreparams(client, command), sendbuf(client), 0; if (!strcmp(args[0], "0")) { - map_find_t f = {0}; - while (map_findfirst(&f, &client->channels) == 1) { - struct channel *chan = f->value; + for (struct channel *chan; (chan = map_pop(&client->channels)); ) channel_part(client, chan, "I fell for a classic prank", NULL); - } - map_findfree(&f); return 0; } char *p = args[0]; @@ -487,12 +461,9 @@ int processPacket(struct client_data *client, char *source, char *command, int a return err_notregistered(client), sendbuf(client), 0; if (!args[0]) { // List pending invites - map_find_t f = {0}; - if (map_findfirst(&f, &client->invites) == 1) - do { - struct channel *chan = f->value; - rpl_invitelist(client, chan), sendbuf(client); - } while(map_findnext(&f) == 1); + struct channel *chan; + map_foreach(&client->invites, 0, &chan) + rpl_invitelist(client, chan), sendbuf(client); return rpl_endofinvitelist(client), sendbuf(client), 0; } if (!args[1]) @@ -736,7 +707,7 @@ int processPacket(struct client_data *client, char *source, char *command, int a if (!map_get(&chan->o, client->key)) return 0; // TODO: error if (argc == 2) { // Type A channel modes - map_find_t f = {0}; + const char *key; int all = !strcmp(args[1], "+0"); int any = 0; if (all) { @@ -745,46 +716,34 @@ int processPacket(struct client_data *client, char *source, char *command, int a any = 1; } if (all || !strcmp(args[1], "+b") || !strcmp(args[1], "b")) { - if (map_findfirst(&f, &chan->listb) == 1) - do { - rpl_banlist(client, chan, f->key), sendbuf(client); - } while(map_findnext(&f) == 1); + map_foreach(&chan->listb, &key, 0) + rpl_banlist(client, chan, key), sendbuf(client); rpl_endofbanlist(client, chan), sendbuf(client); any = 1; } if (all || !strcmp(args[1], "+e") || !strcmp(args[1], "e")) { - if (map_findfirst(&f, &chan->liste) == 1) - do { - rpl_exceptlist(client, chan, f->key), sendbuf(client); - } while(map_findnext(&f) == 1); + map_foreach(&chan->liste, &key, 0) + rpl_exceptlist(client, chan, key), sendbuf(client); rpl_endofexceptlist(client, chan), sendbuf(client); any = 1; } if (all || !strcmp(args[1], "+I") || !strcmp(args[1], "I")) { - if (map_findfirst(&f, &chan->listI) == 1) - do { - rpl_invexlist(client, chan, f->key), sendbuf(client); - } while(map_findnext(&f) == 1); + map_foreach(&chan->listI, &key, 0) + rpl_invexlist(client, chan, key), sendbuf(client); rpl_endofinvexlist(client, chan), sendbuf(client); any = 1; } if (all || !strcmp(args[1], "+q") || !strcmp(args[1], "q")) { - if (map_findfirst(&f, &chan->listq) == 1) - do { - rpl_quietlist(client, chan, f->key), sendbuf(client); - } while(map_findnext(&f) == 1); + map_foreach(&chan->listq, &key, 0) + rpl_quietlist(client, chan, key), sendbuf(client); rpl_endofquietlist(client, chan), sendbuf(client); any = 1; } if (all || !strcmp(args[1], "+w") || !strcmp(args[1], "w")) { - if (map_findfirst(&f, &chan->listwo) == 1) - do { - rpl_accesslist(client, chan, 'o', f->key), sendbuf(client); - } while(map_findnext(&f) == 1); - if (map_findfirst(&f, &chan->listwv) == 1) - do { - rpl_accesslist(client, chan, 'v', f->key), sendbuf(client); - } while(map_findnext(&f) == 1); + map_foreach(&chan->listwo, &key, 0) + rpl_accesslist(client, chan, 'o', key), sendbuf(client); + map_foreach(&chan->listwv, &key, 0) + rpl_accesslist(client, chan, 'v', key), sendbuf(client); rpl_endofaccesslist(client, chan), sendbuf(client); any = 1; } @@ -966,13 +925,10 @@ int processPacket(struct client_data *client, char *source, char *command, int a if (!is_registered(client)) return err_notregistered(client), sendbuf(client), 0; rpl_liststart(client), sendbuf(client); - map_find_t f = {0}; - if (map_findfirst(&f, &channel_map) == 1) - do { - struct channel *chan = f->value; - if (!(chan->dmode & DMODE_SECRET) || map_get(&chan->members, client->key)) - rpl_list(client, chan), sendbuf(client); - } while(map_findnext(&f) == 1); + struct channel *chan; + map_foreach(&channel_map, 0, &chan) + if (!(chan->dmode & DMODE_SECRET) || map_get(&chan->members, client->key)) + rpl_list(client, chan), sendbuf(client); rpl_listend(client), sendbuf(client); } else if(strcmp(command, "NAMES") == 0) { if (!is_registered(client)) @@ -1018,12 +974,9 @@ int processPacket(struct client_data *client, char *source, char *command, int a struct channel *chan = findChannel(args[0]); // TODO: handle chanmode +s, umode +i if (chan) { - map_find_t f = {0}; - if (map_findfirst(&f, &chan->members) == 1) - do { - struct client_data *cl = f->value; - rpl_whoreply(client, cl, chan), sendbuf(client); - } while(map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&chan->members, 0, &cl) + rpl_whoreply(client, cl, chan), sendbuf(client); } } else { struct client_data *cl = findClient(args[0]); @@ -1053,14 +1006,12 @@ int processPacket(struct client_data *client, char *source, char *command, int a rpl_whoisidle(client, cl), sendbuf(client); if (cl->away) rpl_away(client, cl), sendbuf(client); - map_find_t f = {0}; - if (map_findfirst(&f, &cl->channels) == 1) - do { - struct channel *chan = f->value; - if ((cl->umode & UMODE_INVISIBLE || chan->dmode & DMODE_SECRET) && !map_get(&chan->members, client->key)) - continue; - rpl_whoischannels(client, cl, chan), sendbuf(client); - } while (map_findnext(&f) == 1); + struct channel *chan; + map_foreach(&cl->channels, 0, &chan) { + if ((cl->umode & UMODE_INVISIBLE || chan->dmode & DMODE_SECRET) && !map_get(&chan->members, client->key)) + continue; + rpl_whoischannels(client, cl, chan), sendbuf(client); + } if (cl->umode & UMODE_REGISTERED) rpl_whoisaccount(client, cl), sendbuf(client); if (client == cl || client->umode & UMODE_OPER) @@ -1131,11 +1082,9 @@ void newUser(struct client_data *client) { sendLUSERS(client); rpl_umodeis(client), sendbuf(client); sendMOTD(client); - map_find_t f = {0}; - if (map_findfirst(&f, &autojoin) == 1) - do { - channel_join(client, f->key, NULL); - } while (map_findnext(&f) == 1); + const char *key; + map_foreach(&autojoin, &key, 0) + channel_join(client, key, NULL); } void sendLUSERS(struct client_data *client) { @@ -1144,20 +1093,16 @@ void sendLUSERS(struct client_data *client) int invisible = 0; int ops = 0; int channels = 0; - map_find_t f = {0}; - if (map_findfirst(&f, &client_map) == 1) - do { - struct client_data *cl = f->value; - registered++; - if (cl->umode & UMODE_INVISIBLE) - invisible++; - if (cl->umode & UMODE_OPER) - ops++; - } while (map_findnext(&f) == 1); - if (map_findfirst(&f, &client_map) == 1) - do { - channels++; - } while (map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&client_map, 0, &cl) { + registered++; + if (cl->umode & UMODE_INVISIBLE) + invisible++; + if (cl->umode & UMODE_OPER) + ops++; + } + map_foreach(&channel_map, 0, 0) + channels++; for (struct client_data *cl = clients; cl; cl = cl->next) total++; @@ -1218,23 +1163,21 @@ void setNick(struct client_data *client, char* nickname) { sendbuf(client); sendbuf_visible(client); map_unset(&client_map, client->key, NULL); - map_find_t f = {0}; - if (map_findfirst(&f, &client->channels) == 1) - do { - struct channel *chan = f->value; - map_unset(&chan->members, client->key, NULL); - if (map_set(&chan->members, key, client, NULL) == -1) + struct channel *chan; + map_foreach(&client->channels, 0, &chan) { + map_unset(&chan->members, client->key, NULL); + if (map_set(&chan->members, key, client, NULL) == -1) + abort(); + void *old; + map_unset(&chan->o, client->key, &old); + if (old) + if (map_set(&chan->o, key, client, NULL) == -1) + abort(); + map_unset(&chan->v, client->key, &old); + if (old) + if (map_set(&chan->v, key, client, NULL) == -1) abort(); - void *old; - map_unset(&chan->o, client->key, &old); - if (old) - if (map_set(&chan->o, key, client, NULL) == -1) - abort(); - map_unset(&chan->v, client->key, &old); - if (old) - if (map_set(&chan->v, key, client, NULL) == -1) - abort(); - } while(map_findnext(&f) == 1); + } free(client->nick); free(client->key); } @@ -1266,17 +1209,14 @@ void channel_sendtopic(struct client_data *client, struct channel *chan, int joi } void channel_sendnames(struct client_data *client, struct channel *chan) { - map_find_t f = {0}; databuf.len = 0; - if (map_findfirst(&f, &chan->members) == 1) - do { - struct client_data *cl = f->value; - if (rpl_namreply(client, chan, cl)) { - sendbuf(client); - databuf.len = 0; - rpl_namreply(client, chan, cl); - } - } while(map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&chan->members, 0, &cl) + if (rpl_namreply(client, chan, cl)) { + sendbuf(client); + databuf.len = 0; + rpl_namreply(client, chan, cl); + } if (rpl_namreply(client, chan, NULL)) sendbuf(client); rpl_endofnames(client, chan->name); @@ -1383,12 +1323,9 @@ void channel_part(struct client_data *client, struct channel *chan, const char * void channel_kill(struct channel *chan) { map_unset(&channel_map, chan->key, NULL); - map_find_t f = {0}; - if (map_findfirst(&f, &chan->invitees) == 1) - do { - struct client_data *cl = f->value; - map_unset(&cl->invites, chan->key, NULL); - } while(map_findnext(&f) == 1); + struct client_data *cl; + map_foreach(&chan->invitees, 0, &cl) + map_unset(&cl->invites, chan->key, NULL); free(chan->key); free(chan->name); free(chan->topic); diff --git a/src/main.c b/src/main.c index 1d90bb3..82fa512 100644 --- a/src/main.c +++ b/src/main.c @@ -419,14 +419,8 @@ int main(int argc, char *argv[]) #endif free(databuf.buf); /* free any persistent channels */ - { - map_find_t f = {0}; - while (map_findfirst(&f, &channel_map) == 1) { - struct channel *chan = f->value; - channel_kill(chan); - } - map_findfree(&f); - } + for (struct channel *chan; (chan = map_pop(&channel_map)); ) + channel_kill(chan); map_free(&client_map); map_free(&channel_map); map_free(&autojoin); diff --git a/src/map.h b/src/map.h index 0479bc5..751e8d2 100644 --- a/src/map.h +++ b/src/map.h @@ -13,43 +13,34 @@ #ifdef USE_MAP_DYNARR /* all complexity is in terms of n = number of elements */ -struct map_dynarr_value { - char *key; - void *value; -}; -struct map_dynarr { - struct map_dynarr_value *ptr; +typedef struct map_dynarr { + struct map_dynarr_value { + char *key; + void *value; + } *ptr; size_t len, cap; -}; -typedef struct map_dynarr map_t; -struct map_dynarr_find { - char *key; - void *value; - map_t *_root; - size_t _index; -}; -typedef struct map_dynarr_find *map_find_t; -#define map_findfree(f) (free(*(f)), *(f) = 0) +} map_t; +typedef struct map_dynarr_iter { + map_t *root; + size_t index; +} map_iter_t; #else /* all complexity is in terms of n = strlen(key) and s = size of the character set */ -struct trie_node { +typedef struct map_trie_node { unsigned char key; unsigned char len; unsigned char cap; void *value; - struct trie_node *parent; - struct trie_node *data[1]; -}; -typedef struct trie_node *map_t; + struct map_trie_node *parent; + struct map_trie_node *data[1]; +} *map_t; #define TRIE_MAX_KEY 256 -struct trie_find { - struct trie_node *_n; - void *value; - size_t _len; +typedef struct map_trie_iter { + map_t *root; + struct map_trie_node *n; + size_t len; char key[TRIE_MAX_KEY]; -}; -typedef struct trie_find *map_find_t; -#define map_findfree(f) (free(*(f)), *(f) = 0) +} map_iter_t; #endif /* A map abstract data type with following properties: @@ -57,7 +48,6 @@ typedef struct trie_find *map_find_t; * - values are non-NULL pointers * - a NULL value is synonymous with absence of a key * - keys are owned by the map, values are not. - * - traversal can fail with memory allocation errors (sadly) * - the map can't be modified during traversal * * A map is created by allocating and zero-initializing an object of type @@ -82,37 +72,30 @@ NODISCARD int map_set(map_t *root, const char *key, const void *value, void **ol * Trie complexity: O(ns) * Dynarr complexity: O(n) */ void map_free(map_t *root); -/* Traversal functions. - * Return 1 on success, 0 on end, -1 on allocation failure. - * - * Some ground rules: - * - map_find_t should be zero-initialized - * - map_findfirst and map_findfree are idempotent - * - when map_findfirst or map_findnext return 0 or -1, they automatically call - * map_findfree + +/* Iterate over a map. * - * Non-modifying traversal: - * map_find_t f = {0}; - * if (map_findfirst(&f, &map) == 1) - * do { - * value_type *v = f->value; - * // use f->key and v here - * if (gotta_break) { - * map_findfree(&f); // call this when breaking! - * break; - * } - * } while(map_findnext(&f) == 1); + * Do not modify the map while iterating. + * Don't modify *outkey or what it points to, and don't rely on it's lifetime + * being longer than one iteration. + * outvalue is actually a void**, but for implicit casting reasons it's void*. + * Both outkey and outvalue can be specified as NULL. + * Returns 0 on end of iteration, 1 otherwise. + */ +NODISCARD int map_foriter(map_iter_t *f, const char **outkey, void *outvalue); +#define map_foreach(rootp, outkey, outvalue) \ + for (map_iter_t map_itertmp = { .root = rootp }; map_foriter(&map_itertmp, outkey, outvalue); ) +/* Return a value from the map. + * No guarantees about which one! + * You don't get a key and the association is not removed. + * Returns 0 if the map is empty. * - * Emptying traversal: - * while (map_findfirst(&f, &map) == 1) { - * value_type *v = f->value; - * // use f->key and v here - * map_unset(&map, f->key, 0); + * Typical use: + * for (value_type *v; v = map_pop(&map); ) + * map_unset(&map, v->key, 0); + * free(v); * } - * map_findfree(&f); - * - * FIXME: yep, we're silently failing on allocation errors + * map_free(&map); */ -NODISCARD int map_findfirst(map_find_t *pf, map_t *root); -NODISCARD int map_findnext(map_find_t *pf); +NODISCARD void *map_pop(map_t *root); #endif diff --git a/src/map_dynarr.c b/src/map_dynarr.c index 6e6cb1e..ed4e4e4 100644 --- a/src/map_dynarr.c +++ b/src/map_dynarr.c @@ -74,33 +74,18 @@ void map_free(map_t *root) root->ptr = 0; root->len = root->cap = 0; } -int map_findfirst(map_find_t *pf, map_t *root) +int map_foriter(map_iter_t *it, const char **outkey, void *outvalue) { - if (!root->len) + if (it->index == it->root->len) return 0; - map_find_t f; - if (!*pf) { - f = malloc(sizeof(*f)); - if (!f) - return -1; - *pf = f; - } else { - f = *pf; - } - f->_root = root; - f->_index = -1; - return map_findnext(pf); + if (outkey) + *outkey = it->root->ptr[it->index].key; + if (outvalue) + *(void **)outvalue = it->root->ptr[it->index].value; + it->index++; + return 1; } -int map_findnext(map_find_t *pf) +void *map_pop(map_t *root) { - map_find_t f = *pf; - f->_index++; - if (f->_index == f->_root->len) { - *pf = 0; - free(f); - return 0; - } - f->key = f->_root->ptr[f->_index].key; - f->value = f->_root->ptr[f->_index].value; - return 1; + return root->len ? root->ptr[root->len-1].value : 0; } diff --git a/src/map_trie.c b/src/map_trie.c index 2f2dc66..18c7705 100644 --- a/src/map_trie.c +++ b/src/map_trie.c @@ -3,14 +3,14 @@ #include #define trie_is_end(e, n) ((e) >= (n)->len) #define trie_is_found(e, n, k) (!trie_is_end((e), (n)) && (n)->data[(e)]->key == (k)) -#define trie_node_size(cap) (sizeof(struct trie_node)+sizeof(struct trie_node*)*((cap)-1)) -#define trie_data_size(len) (sizeof(struct trie_node*)*(len)) +#define trie_node_size(cap) (sizeof(struct map_trie_node)+sizeof(struct map_trie_node*)*((cap)-1)) +#define trie_data_size(len) (sizeof(struct map_trie_node*)*(len)) // finds the entry for a child node O(log s) // note that there are three cases to handle: // - past the end pointer (key doesn't exist, larger than any existing key) // - ent with different key (key doesn't exist, it should be inserted before this one) // - ent with matching key (key exists) -static int ent_find(struct trie_node *n, int key) +static int ent_find(struct map_trie_node *n, int key) { int lo = 0; int hi = n->len; @@ -28,7 +28,7 @@ static int ent_find(struct trie_node *n, int key) // get value from trie O(n log s) void *map_get(map_t *root, const char *key) { - struct trie_node *n = *root; + struct map_trie_node *n = *root; if (!n) return NULL; while (*key) { @@ -48,7 +48,7 @@ int map_set(map_t *root, const char *key, const void *value, void **oldvalue) return -1; if (oldvalue) *oldvalue = NULL; - struct trie_node *n = *root; + struct map_trie_node *n = *root; if (!n) { // create root node if (!value) return 0; @@ -65,7 +65,7 @@ int map_set(map_t *root, const char *key, const void *value, void **oldvalue) if (!value) // ...unless we're deleting return 0; int cap = key[1] ? 1 : 0; // if it's a leaf, use capacity of 0 - struct trie_node *node = malloc(trie_node_size(cap)); + struct map_trie_node *node = malloc(trie_node_size(cap)); if (!node) { rv = -1; goto cleanup; @@ -77,8 +77,8 @@ int map_set(map_t *root, const char *key, const void *value, void **oldvalue) n->cap = n->cap*2 + 1; // 0 1 3 7 15 31 63 127 255 // we have to update parent's pointer, but ent_find needs that pointer to be valid. // so we have to locate it *before* reallocing. - struct trie_node **pent = n->parent ? &n->parent->data[ent_find(n->parent, n->key)] : root; - struct trie_node *nn = realloc(n, trie_node_size(n->cap)); + struct map_trie_node **pent = n->parent ? &n->parent->data[ent_find(n->parent, n->key)] : root; + struct map_trie_node *nn = realloc(n, trie_node_size(n->cap)); if (!nn) { free(node); rv = -1; @@ -108,7 +108,7 @@ int map_set(map_t *root, const char *key, const void *value, void **oldvalue) while (!n->value && !n->len) { // free no longer used nodes cleanup: if (n->parent) { - struct trie_node *p = n->parent; + struct map_trie_node *p = n->parent; int ent = ent_find(p, n->key); memmove(&p->data[ent], &p->data[ent+1], trie_data_size(--p->len - ent)); free(n); @@ -124,60 +124,58 @@ cleanup: } // free a trie void map_free(map_t *root) { - struct trie_node *n = *root; + struct map_trie_node *n = *root; while (n) { if (n->len) { n = n->data[--n->len]; } else { - struct trie_node *p = n->parent; + struct map_trie_node *p = n->parent; free(n); n = p; } } *root = 0; } -int map_findnext(map_find_t *pf) { - map_find_t f = *pf; +int map_foriter(map_iter_t *f, const char **outkey, void *outvalue) +{ + if (!f->n) { + if (!*f->root) + return 0; + f->n = *f->root; + f->len = 0; + if (outkey) + *outkey = f->key; + if (f->n->value) { + f->key[f->len] = '\0'; + if (outvalue) + *(void **)outvalue = f->n->value; + return 1; + } + } int ent = 0; // go to the first child node for (;;) { - if (!trie_is_end(ent, f->_n)) { - f->_n = f->_n->data[ent]; - f->key[f->_len++] = f->_n->key; - if (f->_n->value) { // found a value - f->key[f->_len] = '\0'; - f->value = f->_n->value; + if (!trie_is_end(ent, f->n)) { + f->n = f->n->data[ent]; + f->key[f->len++] = f->n->key; + if (f->n->value) { // found a value + f->key[f->len] = '\0'; + if (outvalue) + *(void **)outvalue = f->n->value; return 1; } ent = 0; // no value, go to the first child } else { // no more children, go to parent's next child - f->_n = f->_n->parent; - if (!f->_n) { - *pf = NULL; - free(f); + f->n = f->n->parent; + if (!f->n) return 0; - } - f->_len--; - ent = ent_find(f->_n, (unsigned char)f->key[f->_len] + 1); + f->len--; + ent = ent_find(f->n, (unsigned char)f->key[f->len] + 1); } } } -int map_findfirst(map_find_t *pf, map_t *root) { - if (!*root) - return 0; - map_find_t f; - if (*pf) { - f = *pf; - } else { - f = *pf = malloc(sizeof(*f)); - if (!f) - return -1; - } - f->_n = *root; - f->_len = 0; - if (f->_n->value) { - f->key[f->_len] = '\0'; - f->value = f->_n->value; - return 1; - } - return map_findnext(pf); +void *map_pop(map_t *root) +{ + map_iter_t it = { .root = root }; + void *value; + return map_foriter(&it, 0, &value) ? value : 0; } diff --git a/src/net.c b/src/net.c index 2ebaed7..3e51cf4 100644 --- a/src/net.c +++ b/src/net.c @@ -64,21 +64,14 @@ void killConnection(struct client_data *cl, int byChoice) } update_poll_reg(cl); /* Part all channels */ - map_find_t f = {0}; - while (map_findfirst(&f, &cl->channels) == 1) { - struct channel *chan = f->value; + for (struct channel *chan; (chan = map_pop(&cl->channels)); ) channel_part(cl, chan, NULL, NULL); - } - map_findfree(&f); /* Remove from client_map and get rid of the pending invites */ if (cl->key) { map_unset(&client_map, cl->key, NULL); - map_find_t f = {0}; - if (map_findfirst(&f, &cl->invites) == 1) - do { - struct channel *chan = f->value; - map_unset(&chan->invitees, cl->key, NULL); - } while(map_findnext(&f) == 1); + struct channel *chan; + map_foreach(&cl->invites, 0, &chan) + map_unset(&chan->invitees, cl->key, NULL); } map_free(&cl->channels); map_free(&cl->invites); -- 2.56.0