]> PatchyGit - patchyircd.git/commitdiff
irc: use a perfect hash function for command matching
authorEgor <egor@patchysicp.xyz>
Sun, 15 Jun 2025 09:39:38 +0000 (12:39 +0300)
committerEgor <egor@patchysicp.xyz>
Sun, 15 Jun 2025 09:39:38 +0000 (12:39 +0300)
Makefile.am
src/irc.cpp

index d3d9ccc..3d7481d 100644 (file)
@@ -60,3 +60,7 @@ pch.mk: common.hpp.$(PCHEXT)
        @: >pch.mk
 -include pch.mk
 endif
+
+.PHONY: gperf
+gperf:
+       sed -n 's/.*MATCH_COMMAND("\([^"]*\)").*/\1/p' $(srcdir)/src/irc.cpp | gperf -m1 -k1-3
index dea4e3b..b726126 100644 (file)
@@ -236,10 +236,33 @@ static void cont_pass(Client *client, int res) {
                newUser(client);
        }
 }
+#define USE_COMMAND_HASH
+#ifdef USE_COMMAND_HASH
+constexpr size_t command_hash(std::string_view sv) {
+       if (sv.size() < 3)
+               return -1;
+       constexpr unsigned char table[32] = {
+               43, 1, 27, 12, 5, 3,
+               43, 7, 22, 10, 27, 12, 11, 13, 7, 1,
+               0, 16, 15, 0, 0, 0, 11, 3, 43, 43,
+               43, 43, 43, 43, 43, 43,
+       };
+       return table[sv[0]&31] + table[sv[1]&31] + table[sv[2]&31] + sv.size();
+}
+#endif
+
+#ifdef USE_COMMAND_HASH
+#define MATCH_BEGIN switch (command_hash(command)) {
+#define MATCH_COMMAND(s) break; case command_hash(s##sv): if (command == s##sv)
+#define MATCH_ELSE break; default:
+#define MATCH_END break; }
+#else
 #define MATCH_BEGIN if (0)
 #define MATCH_COMMAND(s) else if (command == s##sv)
 #define MATCH_ELSE else
 #define MATCH_END
+#endif
+
 int irc_process_line(Client *client, char *source, std::string_view command, int argc, char *args[]) {
        (void)source;
        databuf.clear();