From 8df9072a8e8fb40a9c0a7d50459ae46a2170dfd3 Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 2 Mar 2025 19:32:12 +0200 Subject: [PATCH] map: move base functions into the class --- src/admin.cpp | 25 +++++------- src/irc.cpp | 20 +++++----- src/main.cpp | 6 +-- src/map.cpp | 61 ++++++++++++---------------- src/map.h | 107 +++++++++++++++++++++----------------------------- src/net.cpp | 6 +-- 6 files changed, 94 insertions(+), 131 deletions(-) diff --git a/src/admin.cpp b/src/admin.cpp index 8257d6d..fcec636 100644 --- a/src/admin.cpp +++ b/src/admin.cpp @@ -14,7 +14,7 @@ static int map_index(lua_State *L) { map_base *m = *(map_base **)luaL_checkudata(L, 1, "map"); const char *key = luaL_checkstring(L, 2); - void *value = map_get(m, key); + void *value = m->_get(key); if (!value) return 0; lua_getiuservalue(L, 1, 1); @@ -40,22 +40,22 @@ static int map_newindex(lua_State *L) const char *key = luaL_checkstring(L, 2); luaL_checkany(L, 3); if (lua_isnil(L, 3)) { - (void)map_set(m, key, 0, 0); + (void)m->_set(key, 0, 0); return 0; } lua_getiuservalue(L, 1, 1); switch (lua_tointeger(L, -1)) { case MAPTYPE_STRINGSET: - (void)map_set(m, key, key, 0); + (void)m->_set(key, key, 0); break; case MAPTYPE_CLIENT: { void **p = (void **)luaL_checkudata(L, 3, "client"); - (void)map_set(m, key, *p, 0); + (void)m->_set(key, *p, 0); break; } case MAPTYPE_CHANNEL: { void **p = (void **)luaL_checkudata(L, 3, "channel"); - (void)map_set(m, key, *p, 0); + (void)m->_set(key, *p, 0); break; } } @@ -63,15 +63,10 @@ static int map_newindex(lua_State *L) } static int map_iter_next(lua_State *L) { - map_iter_t *it = (map_iter_t *)luaL_checkudata(L, 1, "map_iter"); - lua_getiuservalue(L, 1, 2); - const char *key = (const char *)lua_touserdata(L, -1); - lua_pop(L, 1); - void *value; - if (!map_foriter(it, &key, &value)) + map_base::iter *it = (map_base::iter *)luaL_checkudata(L, 1, "map_iter"); + auto [key, value] = it->next(); + if (!value) return 0; - lua_pushlightuserdata(L, (void *)key); - lua_setiuservalue(L, 1, 2); lua_getiuservalue(L, 1, 1); switch (lua_tointeger(L, -1)) { case MAPTYPE_STRINGSET: @@ -95,14 +90,12 @@ static int map_pairs(lua_State *L) { map_base *m = *(map_base **)luaL_checkudata(L, 1, "map"); lua_pushcfunction(L, map_iter_next); - map_iter_t *it = (map_iter_t *)lua_newuserdatauv(L, sizeof(map_iter_t), 2); + map_base::iter *it = (map_base::iter *)lua_newuserdatauv(L, sizeof(map_base::iter), 1); memset(it, 0, sizeof(*it)); it->root = m; luaL_setmetatable(L, "map_iter"); lua_getiuservalue(L, 1, 1); lua_setiuservalue(L, -2, 1); - lua_pushlightuserdata(L, 0); - lua_setiuservalue(L, -2, 2); lua_pushnil(L); return 3; } diff --git a/src/irc.cpp b/src/irc.cpp index 290c8e5..ccd4006 100644 --- a/src/irc.cpp +++ b/src/irc.cpp @@ -1568,16 +1568,16 @@ void channel_kill(struct channel *chan) free(chan->name); free(chan->topic); free(chan->topic_who); - map_free(&chan->members); - map_free(&chan->o); - map_free(&chan->v); - map_free(&chan->listb); - map_free(&chan->liste); - map_free(&chan->listI); - map_free(&chan->listq); - map_free(&chan->listwo); - map_free(&chan->listwv); - map_free(&chan->invitees); + chan->members.clear(); + chan->o.clear(); + chan->v.clear(); + chan->listb.clear(); + chan->liste.clear(); + chan->listI.clear(); + chan->listq.clear(); + chan->listwo.clear(); + chan->listwv.clear(); + chan->invitees.clear(); free(chan->chankey); free(chan); } diff --git a/src/main.cpp b/src/main.cpp index 2eb65c4..e5cb301 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -384,9 +384,9 @@ int main(int argc, char *argv[]) /* free any persistent channels */ for (auto chan : channel_map.pop_view()) channel_kill(chan); - map_free(&client_map); - map_free(&channel_map); - map_free(&autojoin); + client_map.clear(); + channel_map.clear(); + autojoin.clear(); if (fchanlog) fclose(fchanlog); return 0; diff --git a/src/map.cpp b/src/map.cpp index b5e0f4a..20ba22e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -21,68 +21,57 @@ static int ent_find(map_base *root, const char *key, int *found) *found = 0; return lo; } -void *map_get(map_base *root, const char *key) +void *map_base::_get(const char *key) { int found; - int i = ent_find(root, key, &found); - return found ? root->ptr[i].value : 0; + int i = ent_find(this, key, &found); + return found ? ptr[i].value : 0; } -int map_set(map_base *root, const char *key, const void *value, void **oldvalue) +int map_base::_set(const char *key, const void *value, void **oldvalue) { int found; - int i = ent_find(root, key, &found); + int i = ent_find(this, key, &found); if (found) { if (oldvalue) - *oldvalue = root->ptr[i].value; + *oldvalue = ptr[i].value; if (!value) { - free(root->ptr[i].key); - memmove(root->ptr+i, root->ptr+i+1, sizeof(struct map_value)*(root->len-(i+1))); - root->len--; + free(ptr[i].key); + memmove(ptr+i, ptr+i+1, sizeof(struct map_value)*(len-(i+1))); + len--; } else { - root->ptr[i].value = (void *)value; + ptr[i].value = (void *)value; } } else { if (oldvalue) *oldvalue = 0; if (value) { - if (root->len == root->cap) { - int ncap = root->cap ? root->cap*2 : 2; - struct map_value *nptr = (struct map_value *)realloc(root->ptr, sizeof(struct map_value)*ncap); + if (len == cap) { + int ncap = cap ? cap*2 : 2; + struct map_value *nptr = (struct map_value *)realloc(ptr, sizeof(struct map_value)*ncap); if (!nptr) return -1; - root->ptr = nptr; - root->cap = ncap; + ptr = nptr; + cap = ncap; } int slen = strlen(key)+1; char *nkey = (char *)malloc(slen); if (!nkey) return -1; memcpy(nkey, key, slen); - memmove(root->ptr+i+1, root->ptr+i, sizeof(struct map_value)*(root->len-i)); - root->len++; - root->ptr[i].key = nkey; - root->ptr[i].value = (void *)value; + memmove(ptr+i+1, ptr+i, sizeof(struct map_value)*(len-i)); + len++; + ptr[i].key = nkey; + ptr[i].value = (void *)value; } } return 0; } -void map_free(map_base *root) +void map_base::clear() { - while (root->len) { - free(root->ptr[--root->len].key); + while (len) { + free(ptr[--len].key); } - free(root->ptr); - root->ptr = 0; - root->len = root->cap = 0; -} -int map_foriter(map_iter_t *it, const char **outkey, void *outvalue) -{ - if (it->index == it->root->len) - return 0; - if (outkey) - *outkey = it->root->ptr[it->index].key; - if (outvalue) - *(void **)outvalue = it->root->ptr[it->index].value; - it->index++; - return 1; + free(ptr); + ptr = 0; + len = cap = 0; } diff --git a/src/map.h b/src/map.h index 475311e..07b272a 100644 --- a/src/map.h +++ b/src/map.h @@ -1,29 +1,8 @@ #ifndef MAP_H_ #define MAP_H_ -#include -#if defined(__has_c_attribute) -# if __has_c_attribute(nodiscard) -# define NODISCARD [[nodiscard]] -# else -# define NODISCARD -# endif -#else -# define NODISCARD -#endif - -/* all complexity is in terms of n = number of elements */ -struct map_value { - char *key; - void *value; -}; -struct map_base { - struct map_value *ptr; - size_t len, cap; -}; -typedef struct map_iter { - map_base *root; - size_t index; -} map_iter_t; +#include +#include +#include /* A map abstract data type with following properties: * - keys are lexicographically-sorted unique NUL-terminated strings @@ -35,37 +14,40 @@ typedef struct map_iter { * A map is created by allocating and zero-initializing an object of type * map_t. All map functions take a pointer to map_t. */ - -/* Return the associated value for a given key. - * Dynarr complexity: O(log n) */ -void *map_get(map_base *root, const char *key); -/* Associate a new value with a given key. - * Returns 0 on success, -1 on allocation error. - * If oldvalue is not NULL, it receives the old value of key. - * No allocation failures on value = NULL. - * Dynarr complexity: O(n) */ -NODISCARD int map_set(map_base *root, const char *key, const void *value, void **oldvalue); -/* Removes all keys from the map and frees any associated memory. - * The map_t is reset to zero-initialized state and can be used again. - * Dynarr complexity: O(n) */ -void map_free(map_base *root); - -/* Iterate over a map. - * - * 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); - -#include -#include -#include -struct client_data; -struct channel; +struct map_value { + char *key; + void *value; +}; +struct map_base { + struct map_value *ptr; + size_t len, cap; + /* Return the associated value for a given key. + * Dynarr complexity: O(log n) */ + void *_get(const char *key); + /* Associate a new value with a given key. + * Returns 0 on success, -1 on allocation error. + * If oldvalue is not NULL, it receives the old value of key. + * No allocation failures on value = NULL. + * Dynarr complexity: O(n) */ + [[nodiscard]] int _set(const char *key, const void *value, void **oldvalue); + /* Removes all keys from the map and frees any associated memory. + * The map_t is reset to zero-initialized state and can be used again. + * Dynarr complexity: O(n) */ + void clear(); + /* Iterate over a map. + * Do not modify the map while iterating. + */ + struct iter { + map_base *root; + size_t index; + auto next() { + map_value kv{0, 0}; + if (index < root->len) + kv = root->ptr[index++]; + return std::make_pair(kv.key, kv.value); + } + }; +}; template struct map_base2 : map_base { @@ -96,9 +78,6 @@ struct map_base2 : map_base { auto pop_view() { return reverse{*this}; } - void clear() { - map_free(this); - } size_t size() { return len; } @@ -111,31 +90,33 @@ protected: } public: bool has(V v) { - return !!map_get(this, T::to_key(v)); + return !!_get(T::to_key(v)); } bool add(V v) { void *old; - if (map_set(this, T::to_key(v), v, &old) == -1) + if (_set(T::to_key(v), v, &old) == -1) abort(); return !old; } bool remove(V v) { void *old; - (void)map_set(this, T::to_key(v), 0, &old); + (void)_set(T::to_key(v), 0, &old); return !!old; } V get(const char *k) { - return (V)map_get(this, k); + return (V)_get(k); } }; +struct client_data; struct clientmap : map_base2 { void rename(struct client_data *v, const char *newk) { - if (remove(v) && map_set(this, newk, v, 0) == -1) + if (remove(v) && _set(newk, v, 0) == -1) abort(); } }; +struct channel; struct channelmap : map_base2 { }; struct stringset : map_base2 { diff --git a/src/net.cpp b/src/net.cpp index f0ab00b..135a91d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -78,9 +78,9 @@ void killConnection(struct client_data *cl, int byChoice) for (auto chan : cl->invites) chan->invitees.remove(cl); } - map_free(&cl->channels); - map_free(&cl->invites); - map_free(&cl->monitor); + cl->channels.clear(); + cl->invites.clear(); + cl->monitor.clear(); killConnectionPart2(cl); } void killConnectionPart2(struct client_data *cl) -- 2.56.0