]> PatchyGit - patchyircd.git/commitdiff
map: get rid of map_base2
authorEgor <egor@patchysicp.xyz>
Sun, 8 Feb 2026 13:28:45 +0000 (15:28 +0200)
committerEgor <egor@patchysicp.xyz>
Sun, 8 Feb 2026 13:28:45 +0000 (15:28 +0200)
src/admin.cpp
src/irc.cpp
src/irc.hpp
src/ircdata.hpp
src/map.hpp
src/net.cpp

index e37bcd2..9292540 100644 (file)
@@ -44,7 +44,7 @@ static void push(lua_State *L, Channel *chan);
 
 template<typename T>
 struct SetRef {
-       map_base2<T> &s;
+       FlatSet<T, SetValueLess<T>> &s;
 
        static consteval const char *get_mtname() {
                if constexpr (std::same_as<T, std::string>) {
@@ -61,24 +61,25 @@ struct SetRef {
 
        int index(lua_State *L) {
                std::string_view key = checkstringview(L, 2);
-               if (!s.has(key))
+               if (!s.contains(key))
                        return 0;
-               push(L, s.get(key));
+               auto it = s.find(key);
+               push(L, it != s.end() ? *it : T());
                return 1;
        }
        int newindex(lua_State *L) {
                std::string_view key = checkstringview(L, 2);
                luaL_checkany(L, 3);
                if (lua_isnil(L, 3)) {
-                       s.remove(key);
+                       s.erase(key);
                        return 0;
                }
                if constexpr (std::same_as<T, std::string>) {
-                       s.add(key);
+                       s.insert(key);
                } else if constexpr (std::same_as<T, Client*>) {
-                       s.add(*(Client **)luaL_checkudata(L, 3, "Client"));
+                       s.insert(*(Client **)luaL_checkudata(L, 3, "Client"));
                } else if constexpr (std::same_as<T, Channel*>) {
-                       s.add(*(Channel **)luaL_checkudata(L, 3, "Channel"));
+                       s.insert(*(Channel **)luaL_checkudata(L, 3, "Channel"));
                } else {
                        static_assert(false);
                }
@@ -100,10 +101,9 @@ struct SetRef {
                size_t index = 0;
                int next(lua_State *L) {
                        lua_getiuservalue(L, 1, 1);
-                       SetRef &ref = *static_cast<SetRef *>(lua_touserdata(L, -1));
-                       auto &m = ref.s.m;
-                       auto it = m.begin() + index;
-                       if (it == m.end())
+                       auto &s = static_cast<SetRef *>(lua_touserdata(L, -1))->s;
+                       auto it = s.begin() + index;
+                       if (it == s.end())
                                return 0;
                        index++;
                        push(L, to_key(*it));
@@ -119,7 +119,7 @@ struct SetRef {
                lua_pushnil(L);
                return 3;
        }
-       static void _push(lua_State *L, map_base2<T> &s) {
+       static void _push(lua_State *L, FlatSet<T, SetValueLess<T>> &s) {
                pushreftype<SetRef>(L, s);
        }
        static void regmt(lua_State *L) {
@@ -138,7 +138,7 @@ struct SetRef {
        }
 };
 template<typename T>
-static void push(lua_State *L, map_base2<T> &s) {
+static void push(lua_State *L, FlatSet<T, SetValueLess<T>> &s) {
        SetRef<T>::_push(L, s);
 }
 
@@ -330,12 +330,13 @@ static int fn_channel_new(lua_State *L)
        size_t chanlen = strlen(channel);
        if (chanlen > 32)
                luaL_error(L, "channel name length too long!");
-       char key[33];
-       memcpy(key, channel, chanlen+1);
-       stringlower(key);
-       Channel *chan = channel_map.get(key);
-       if (!chan)
+       Channel *chan = findChannel(channel);
+       if (!chan) {
+               char key[33];
+               memcpy(key, channel, chanlen+1);
+               stringlower(key);
                chan = new Channel(channel, key, creation ? creation : get_time());
+       }
        return 0;
 }
 static int fn_channel_mode(lua_State *L)
index 72cbbcb..2e85411 100644 (file)
@@ -8,8 +8,8 @@
 #include "job.hpp"
 #include "admin.hpp"
 std::vector<char> databuf;
-clientmap client_map = {};
-channelmap channel_map = {};
+clientset client_map = {};
+channelset channel_map = {};
 
 const char *hostname = 0;
 void sendbuf(Client *client) {
@@ -37,7 +37,7 @@ static void sendbuf_chan_caps(Channel *chan, unsigned positive, unsigned negativ
 static void sendbuf_chan(Channel *chan) {
        sendbuf_chan_caps(chan, 0, 0);
 }
-static void sendbuf_list_sans_self_caps(Client *client, clientmap &ls, int cookie, int positive, int negative) {
+static void sendbuf_list_sans_self_caps(Client *client, clientset &ls, int cookie, int positive, int negative) {
        for (auto cl : ls)
                if (client != cl) {
                        if (cookie) {
@@ -50,13 +50,13 @@ static void sendbuf_list_sans_self_caps(Client *client, clientmap &ls, int cooki
                                sendbuf(cl);
                }
 }
-static void sendbuf_list_sans_self(Client *client, clientmap &ls, int cookie) {
+static void sendbuf_list_sans_self(Client *client, clientset &ls, int cookie) {
        sendbuf_list_sans_self_caps(client, ls, cookie, 0, 0);
 }
 void sendbuf_monitor(const char *nick, int cookie, int positive, int negative)
 {
        for (auto cl : client_map)
-               if (cl->monitor.has(nick)) {
+               if (cl->monitor.contains(nick)) {
                        if (cookie) {
                                if (cookie != cl->cookie)
                                        cl->cookie = cookie;
@@ -608,9 +608,9 @@ saslcleanup:
                Channel *chan = findChannel(args[0]);
                if (!chan)
                        return err_nosuchchannel(client, args[0]), sendbuf(client), false;
-               if (!chan->members.has(client))
+               if (!chan->members.contains(client))
                        return err_notonchannel(client, chan), sendbuf(client), false;
-               chan->o.add(client);
+               chan->o.insert(client);
                copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick);
                sendbuf_chan(chan);
        } MATCH_COMMAND("JOIN") {
@@ -662,7 +662,7 @@ saslcleanup:
                        channel_sendtopic(client, chan, 0);
                } else {
                        // TODO: membership check, maybe?
-                       if (chan->dmode & DMODE_TOPICPROT && !chan->o.has(client))
+                       if (chan->dmode & DMODE_TOPICPROT && !chan->o.contains(client))
                                return false; // FIXME: error 482
                        channel_topic(client, chan, args[1], client->nick, get_time());
                }
@@ -681,19 +681,19 @@ saslcleanup:
                if (!chan)
                        return err_nosuchchannel(client, args[1]), sendbuf(client), false;
                if (chan->dmode & DMODE_INVITEONLY) {
-                       if (!chan->o.has(client))
+                       if (!chan->o.contains(client))
                                return err_chanoprivsneeded(client, chan), sendbuf(client), false;
                } else {
-                       if (!chan->members.has(client))
+                       if (!chan->members.contains(client))
                                return err_notonchannel(client, chan), sendbuf(client), false;
                }
                Client *cl = findClient(args[0]);
                if (!cl)
                        return err_nosuchnick(client, args[0]), sendbuf(client), false;
-               if (chan->members.has(cl))
+               if (chan->members.contains(cl))
                        return err_useronchannel(client, cl->nick, chan), sendbuf(client), false;
-               chan->invitees.add(cl);
-               cl->invites.add(chan);
+               chan->invitees.insert(cl);
+               cl->invites.insert(chan);
                rpl_inviting(client, cl, chan);
                sendbuf(client);
                msg_invite(client, cl, chan);
@@ -707,9 +707,9 @@ saslcleanup:
                Channel *chan = findChannel(args[0]);
                if (!chan)
                        return err_nosuchchannel(client, args[0]), sendbuf(client), false;
-               if (!chan->o.has(client))
+               if (!chan->o.contains(client))
                        return err_chanoprivsneeded(client, chan), sendbuf(client), false;
-               if (!chan->members.has(client))
+               if (!chan->members.contains(client))
                        return err_notonchannel(client, chan), sendbuf(client), false;
                char *p = args[1];
                do {
@@ -750,11 +750,11 @@ privmsg_notice_common:
                        if (match_list(client, chan->listb) && !match_list(client, chan->liste))
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), false;
                        if (chan->dmode & DMODE_INVITEONLY
-                                       && !chan->invitees.has(client) && !match_list(client, chan->listI))
+                                       && !chan->invitees.contains(client) && !match_list(client, chan->listI))
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), false;
-                       if (chan->dmode & DMODE_NOEXTERNAL && !chan->members.has(client))
+                       if (chan->dmode & DMODE_NOEXTERNAL && !chan->members.contains(client))
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), false;
-                       if (chan->dmode & DMODE_MODERATED && !chan->v.has(client) && !chan->o.has(client))
+                       if (chan->dmode & DMODE_MODERATED && !chan->v.contains(client) && !chan->o.contains(client))
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), false;
                        switch (admin_hook("sendtochannel", client, 0, chan, args[1])) {
                        case -1:
@@ -941,7 +941,7 @@ privmsg_notice_common:
                                Channel *chan = findChannel(nick);
                                if (!chan)
                                        return err_nosuchchannel(client, nick), sendbuf(client), false;
-                               if (!chan->o.has(client))
+                               if (!chan->o.contains(client))
                                        return false; // TODO: error
                                if (argc == 2) { // Type A channel modes
                                        int all = !strcmp(args[1], "+0");
@@ -994,7 +994,7 @@ privmsg_notice_common:
                        return err_notregistered(client), sendbuf(client), false;
                rpl_liststart(client), sendbuf(client);
                for (auto chan : channel_map)
-                       if (client->umode & UMODE_OPER || !(chan->dmode & DMODE_SECRET) || chan->members.has(client))
+                       if (client->umode & UMODE_OPER || !(chan->dmode & DMODE_SECRET) || chan->members.contains(client))
                                rpl_list(client, chan), sendbuf(client);
                rpl_listend(client), sendbuf(client);
        } MATCH_COMMAND("NAMES") {
@@ -1008,7 +1008,7 @@ privmsg_notice_common:
                        if ((p = strchr(channel, ',')))
                                *p++ = '\0';
                        Channel *chan = findChannel(channel);
-                       if (chan && (!(chan->dmode & DMODE_SECRET) || chan->members.has(client))) {
+                       if (chan && (!(chan->dmode & DMODE_SECRET) || chan->members.contains(client))) {
                                channel_sendnames(client, chan);
                        } else {
                                rpl_endofnames(client, channel);
@@ -1055,7 +1055,7 @@ privmsg_notice_common:
                                int visible = client->umode & UMODE_OPER || !(cl->umode & UMODE_INVISIBLE) || client == cl;
                                if (!visible) {
                                        for (auto chan : cl->channels) {
-                                               if (client->channels.has(chan)) {
+                                               if (client->channels.contains(chan)) {
                                                        visible = 1;
                                                        break;
                                                }
@@ -1090,7 +1090,7 @@ privmsg_notice_common:
                        if (cl->away)
                                rpl_away(client, cl), sendbuf(client);
                        for (auto chan : cl->channels) {
-                               if ((cl->umode & UMODE_INVISIBLE || chan->dmode & DMODE_SECRET) && !chan->members.has(client))
+                               if ((cl->umode & UMODE_INVISIBLE || chan->dmode & DMODE_SECRET) && !chan->members.contains(client))
                                        continue;
                                rpl_whoischannels(client, cl, chan), sendbuf(client);
                        }
@@ -1143,8 +1143,8 @@ privmsg_notice_common:
                                        return rpl_monlistfull(client, MONITOR_LIMIT,nick), sendbuf(client), false;
                                if ((p = strchr(nick, ',')))
                                        *p++ = '\0';
-                               client->monitor.add(nick);
-                               Client *cl = client_map.get(nick);
+                               client->monitor.insert(nick);
+                               Client *cl = findClientByKey(nick);
                                if (cl)
                                        rpl_mononline(client, cl), sendbuf(client);
                                else
@@ -1163,7 +1163,7 @@ privmsg_notice_common:
                                char *nick = p;
                                if ((p = strchr(nick, ',')))
                                        *p++ = '\0';
-                               client->monitor.remove(nick);
+                               client->monitor.erase(nick);
                        } while (p);
                        break;
                }
@@ -1177,7 +1177,7 @@ privmsg_notice_common:
                        break;
                case 'S':
                        for (auto& key : client->monitor) {
-                               Client *cl = client_map.get(key);
+                               Client *cl = findClientByKey(key);
                                if (cl)
                                        rpl_mononline(client, cl), sendbuf(client);
                                else
@@ -1330,7 +1330,7 @@ void setNick(Client *client, char* nickname) {
                return;
        }
 
-       if (Client *other = client_map.get(LowercasingView(nickname)); other) {
+       if (Client *other = findClient(nickname); other) {
                if (client != other)
                        err_nicknameinuse(client, nickname), sendbuf(client);
                return;
@@ -1352,11 +1352,12 @@ void setNick(Client *client, char* nickname) {
                sendbuf(client);
                sendbuf_visible(client);
                rpl_monoffline(0, client->key), sendbuf_monitor(client->key, 0, 0, 0);
-               client_map.remove(client);
+               client_map.erase(client);
                for (auto chan : client->channels) {
-                       chan->members.rename(client, key);
-                       chan->o.rename(client, key);
-                       chan->v.rename(client, key);
+                       renameClient(chan->members, client, key);
+                       renameClient(chan->o, client, key);
+                       renameClient(chan->v, client, key);
+                       renameClient(chan->invitees, client, key);
                }
                delete[] client->nick;
                delete[] client->key;
@@ -1367,7 +1368,7 @@ void setNick(Client *client, char* nickname) {
        client->nick = mystrdup(nickname);
        updateNuh(client);
        client->key = mystrdup(key);
-       client_map.add(client);
+       client_map.insert(client);
        rpl_mononline(0, client), sendbuf_monitor(client->key, 0, 0, 0);
 }
 /* changes username, hostname or both
@@ -1425,11 +1426,11 @@ void client_chghost(Client *client, const char *newusername, const char *newhost
                        sendbuf_list_sans_self_caps(client, chan->members, 0, 0, CAP_EXTENDEDJOIN|CAP_CHGHOST);
                        msg_join_extended(client, chan);
                        sendbuf_list_sans_self_caps(client, chan->members, 0, CAP_EXTENDEDJOIN, CAP_CHGHOST);
-                       if (chan->v.has(client)) {
+                       if (chan->v.contains(client)) {
                                copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +v %s\r\n", chan->name, client->nick);
                                sendbuf_list_sans_self_caps(client, chan->members, 0, 0, CAP_CHGHOST);
                        }
-                       if (chan->o.has(client)) {
+                       if (chan->o.contains(client)) {
                                copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick);
                                sendbuf_list_sans_self_caps(client, chan->members, 0, 0, CAP_CHGHOST);
                        }
@@ -1489,17 +1490,17 @@ void channel_join(Client *client, const char *channel, const char *chankey)
        size_t chanlen = strlen(channel);
        if (chanlen >= MAX_CHANLEN)
                return err_badchanmask(client, channel), sendbuf(client);
-       char key[MAX_CHANLEN];
-       memcpy(key, channel, chanlen+1);
-       stringlower(key);
-       Channel *chan = channel_map.get(key);
+       Channel *chan = findChannel(channel);
        int newchan = !chan;
        if (!chan) {
+               char key[MAX_CHANLEN];
+               memcpy(key, channel, chanlen+1);
+               stringlower(key);
                chan = new Channel(channel, key, get_time());
                chan->dmode &= ~DMODE_PERSIST;
-               chan->o.add(client);
+               chan->o.insert(client);
        } else {
-               if (chan->members.has(client))
+               if (chan->members.contains(client))
                        return;
                if (chan->chankey && (!chankey || strcmp(chan->chankey, chankey) == 0))
                        return err_badchannelkey(client, chan), sendbuf(client);
@@ -1508,11 +1509,11 @@ void channel_join(Client *client, const char *channel, const char *chankey)
                if (match_list(client, chan->listb) && !match_list(client, chan->liste))
                        return err_bannedfromchan(client, chan), sendbuf(client);
                if (chan->dmode & DMODE_INVITEONLY
-                               && !chan->invitees.has(client) && !match_list(client, chan->listI))
+                               && !chan->invitees.contains(client) && !match_list(client, chan->listI))
                        return err_inviteonlychan(client, chan), sendbuf(client);
        }
-       chan->members.add(client);
-       client->channels.add(chan);
+       chan->members.insert(client);
+       client->channels.insert(chan);
        chan->member_count++;
        // send JOIN to everyone
        msg_join(client, chan);
@@ -1529,12 +1530,12 @@ void channel_join(Client *client, const char *channel, const char *chankey)
        // TODO: send channel modes to the joining client
        // apply +w modes
        if (match_list(client, chan->listwo)) {
-               chan->o.add(client);
+               chan->o.insert(client);
                copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +o %s\r\n", chan->name, client->nick);
                sendbuf_chan(chan);
        }
        if (match_list(client, chan->listwv)) {
-               chan->v.add(client);
+               chan->v.insert(client);
                copy_strf(&databuf, ":cia!cia@cia.gov MODE %s +v %s\r\n", chan->name, client->nick);
                sendbuf_chan(chan);
        }
@@ -1546,11 +1547,11 @@ void channel_join(Client *client, const char *channel, const char *chankey)
 Channel::Channel(const char *channel, const char *key, time_t creation)
        :key(mystrdup(key)), name(mystrdup(channel)), creation(creation)
 {
-       channel_map.add(this);  
+       channel_map.insert(this);       
 }
 void channel_part(Client *client, Channel *chan, const char *reason, Client *kicker)
 {
-       if (!chan->members.has(client))
+       if (!chan->members.contains(client))
                return;
        if (kicker) {
                msg_kick(kicker, client, chan, reason);
@@ -1559,18 +1560,18 @@ void channel_part(Client *client, Channel *chan, const char *reason, Client *kic
                msg_part(client, chan, *reason ? reason : NULL);
                sendbuf_chan(chan);
        }
-       client->channels.remove(chan);
-       chan->members.remove(client);
-       chan->o.remove(client);
-       chan->v.remove(client);
+       client->channels.erase(chan);
+       chan->members.erase(client);
+       chan->o.erase(client);
+       chan->v.erase(client);
        chan->member_count--;
        if (!chan->member_count && !(chan->dmode & DMODE_PERSIST))
                delete chan;
 }
 Channel::~Channel() {
-       channel_map.remove(this);
+       channel_map.erase(this);
        for (auto cl : invitees)
-               cl->invites.remove(this);
+               cl->invites.erase(this);
        delete[] key;
        delete[] name;
        delete[] topic;
@@ -1695,9 +1696,9 @@ void channel_mode(Client *client, Channel *chan, char *args[]) {
                                break; // TODO: error msg
                        stringlower(mask);
                        if (is_plus)
-                               list->add(mask);
+                               list->insert(mask);
                        else
-                               list->remove(mask);
+                               list->erase(mask);
                        char which[2] = {*p, 0};
                        copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n",
                                        n, u, h, chan->name, is_plus?"+":"-", which, mask);
@@ -1717,16 +1718,16 @@ void channel_mode(Client *client, Channel *chan, char *args[]) {
                                        err_nosuchnick(client, nick), sendbuf(client);
                                break;
                        }
-                       if (!chan->members.has(cl)) {
+                       if (!chan->members.contains(cl)) {
                                if (client)
                                        err_usernotinchannel(client, cl->nick, chan), sendbuf(client);
                                break;
                        }
-                       clientmap &clmap = *p == 'o' ? chan->o : chan->v;
+                       clientset &clset = *p == 'o' ? chan->o : chan->v;
                        if (is_plus)
-                               clmap.add(cl);
+                               clset.insert(cl);
                        else
-                               clmap.remove(cl);
+                               clset.erase(cl);
                        copy_strf(&databuf, ":%s!%s@%s MODE %s %s%s %s\r\n",
                                        n, u, h, chan->name, is_plus?"+":"-", which, cl->nick);
                        sendbuf_chan(chan);
@@ -1761,9 +1762,15 @@ void channel_topic(Client *src, Channel *chan, const char *topic, const char *wh
        chanlog_time(chan->topic_when);
        sendbuf_chan(chan);
 }
-Client *findClient(const char *nickname) {
-       return client_map.get(LowercasingView(nickname));
+Client *findClientByKey(std::string_view key) {
+       auto it = client_map.find(key);
+       return it != client_map.end() ? *it : nullptr;
+}
+Client *findClient(std::string_view nickname) {
+       auto it = client_map.find(LowercasingView(nickname));
+       return it != client_map.end() ? *it : nullptr;
 }
-Channel *findChannel(const char *channel) {
-       return channel_map.get(LowercasingView(channel));
+Channel *findChannel(std::string_view channel) {
+       auto it = channel_map.find(LowercasingView(channel));
+       return it != channel_map.end() ? *it : nullptr;
 }
index 0360d55..89d8fcf 100644 (file)
@@ -16,8 +16,9 @@ void sendLUSERS(Client *client);
 void sendMOTD(Client *client);
 void setNick(Client *client, char* nickname);
 void client_chghost(Client *client, const char *newusername, const char *newhostname);
-Client *findClient(const char *nickname);
-Channel *findChannel(const char *channel);
+Client *findClientByKey(std::string_view key);
+Client *findClient(std::string_view nickname);
+Channel *findChannel(std::string_view channel);
 void channel_sendtopic(Client *client, Channel *chan, int joining);
 void channel_sendnames(Client *client, Channel *chan);
 void channel_join(Client *client, const char *channel, const char *chankey);
index 02af147..a9990fc 100644 (file)
@@ -54,8 +54,8 @@ struct Client {
        size_t wlen = 0;
        char   umode = 0;
        char   regstate = REG_INIT;
-       channelmap channels;
-       channelmap invites;
+       channelset channels;
+       channelset invites;
        stringset monitor;
        int    cookie = 0;
        time_t signon = 0;
@@ -93,9 +93,9 @@ struct Channel {
        char *topic_who = nullptr;
        time_t topic_when = 0;
        time_t creation = 0;
-       clientmap members;
-       clientmap o;
-       clientmap v;
+       clientset members;
+       clientset o;
+       clientset v;
        int member_count = 0;
        char dmode = DMODE_NOEXTERNAL | DMODE_TOPICPROT | DMODE_PERSIST;
        stringset listb;
@@ -104,7 +104,7 @@ struct Channel {
        stringset listq;
        stringset listwo;
        stringset listwv;
-       clientmap invitees;
+       clientset invitees;
        char *chankey = nullptr;
        int member_limit = -1;
 
@@ -113,18 +113,18 @@ struct Channel {
        ~Channel();
 
        bool is_op(Client *client) {
-               return o.has(client);
+               return o.contains(client);
        }
        bool is_voice(Client *client) {
-               return v.has(client);
+               return v.contains(client);
        }
 };
 constexpr std::string_view to_key(const Channel *v) noexcept {
        return v->key;
 }
 
-extern clientmap client_map;
-extern channelmap channel_map;
+extern clientset client_map;
+extern channelset channel_map;
 extern Client  *clients;
 extern Client  *dyingclients;
 #endif
index c2ea4a8..0cb41f3 100644 (file)
@@ -150,16 +150,6 @@ public:
        FlatSet& operator=(FlatSet&&) = delete;
 };
 
-/* A map abstract data type with following properties:
- * - keys are lexicographically-sorted unique NUL-terminated strings
- * - values are non-NULL pointers
- * - a NULL value is synonymous with absence of a key
- * - keys are owned by the map, values are not.
- * - the map can't be modified during traversal
- *
- * A map is created by allocating and zero-initializing an object of type
- * map_t. All map functions take a pointer to map_t.
- */
 struct Client;
 struct Channel;
 constexpr std::string_view to_key(const std::string &v) noexcept {
@@ -169,7 +159,7 @@ constexpr std::string_view to_key(const Client *v) noexcept;
 constexpr std::string_view to_key(const Channel *v) noexcept;
 
 template<typename T>
-struct MapValueLess {
+struct SetValueLess {
        using is_transparent = void;
        constexpr bool operator()(const T& lhs, const T& rhs) noexcept {
                return to_key(lhs) < to_key(rhs);
@@ -194,65 +184,35 @@ struct MapValueLess {
        }
 };
 
-template<typename T>
-struct map_base2 {
-       map_base2& operator=(map_base2&&) = delete;
-       FlatSet<T, MapValueLess<T>> m;
-
-       void clear() {
-               m.clear();
-       }
-
-       using value_type = T;
-       auto begin() { return m.begin(); }
-       auto end() { return m.end(); }
-       auto rbegin() { return m.rbegin(); }
-       auto rend() { return m.rend(); }
-       size_t size() {
-               return m.size();
-       }
-       template<typename K>
-       bool has(const K& k) {
-               return m.contains(k);
-       }
-       template<typename K>
-       void add(const K &v) {
-               m.insert(v);
-       }
-       template<typename K>
-       void remove(const K &k) {
-               m.erase(k);
-       }
-
-       template<typename K>
-       T get(const K& k) {
-               auto it = m.find(k);
-               return it != m.end() ? *it : T();
-       }
-};
-
-struct clientmap : map_base2<Client *> {
-       void rename(Client *v, const char *newk) {
-               auto it1 = m.find(v);
-               if (it1 == m.end())
-                       return;
-               auto it2 = m.lower_bound(std::string_view(newk));
-               // Have to to this with a const_cast on the underlying vector, instead
-               // of m.extract/m.replace, because it's UB to replace with an unsorted
-               // vector. This will be an actual problem in e.g. libcxx with hardening
-               // enabled, since they assert that the array is sorted.
-               Client **p = const_cast<Client **>(&*it1);
-               Client **q = const_cast<Client **>(&*it2);
-               if (p < q)
-                       std::rotate(p, p+1, q);
-               else
-                       std::rotate(q, p, p+1);
-       }
-};
-using channelmap = map_base2<Channel *>;
-struct stringset : map_base2<std::string> {
-       template<typename K>
-       std::string get(const K& k) = delete;
-};
+using clientset = FlatSet<Client *, SetValueLess<Client *>>;
+using channelset = FlatSet<Channel *, SetValueLess<Channel *>>;
+using stringset = FlatSet<std::string, SetValueLess<std::string>>;
+/**
+ * Move a client to a different key position in the set.
+ * 
+ * When a user updates the nickname (setNick()) we have to update all sets
+ * referencing the user. Rather than removing and readding the user, we simply
+ * put him at the position of the new key. This temporarily breaks the
+ * invariant of flat_set. The benefit is that we don't have to track the list
+ * of sets we have to readd the user to.
+ *
+ * This function is a no-op when the client isn't a member of the set.
+ */
+inline void renameClient(clientset &s, Client *cl, std::string_view newk) {
+       auto it1 = s.find(cl);
+       if (it1 == s.end())
+               return;
+       auto it2 = s.lower_bound(newk);
+       // Have to to this with a const_cast on the underlying vector, instead
+       // of m.extract/m.replace, because it's UB to replace with an unsorted
+       // vector. This will be an actual problem in e.g. libcxx with hardening
+       // enabled, since they assert that the array is sorted.
+       Client **p = const_cast<Client **>(&*it1);
+       Client **q = const_cast<Client **>(&*it2);
+       if (p < q)
+               std::rotate(p, p+1, q);
+       else
+               std::rotate(q, p, p+1);
+}
 
 #endif
index f6d0e80..0033c86 100644 (file)
@@ -78,10 +78,10 @@ void killConnection(Client *cl, int byChoice)
        /* Remove from client_map and get rid of the pending invites */
        if (cl->key) {
                admin_hook("nickdel", cl, 0, 0, cl->key);
-               client_map.remove(cl);
+               client_map.erase(cl);
                rpl_monoffline(0, cl->key), sendbuf_monitor(cl->key, 0, 0, 0);
                for (auto chan : cl->invites)
-                       chan->invitees.remove(cl);
+                       chan->invitees.erase(cl);
        }
        cl->channels.clear();
        cl->invites.clear();