From 931cb6e71b72035013c9433e39264a9b33e2b89b Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 15 Jun 2025 12:39:38 +0300 Subject: [PATCH] irc: use a perfect hash function for command matching --- Makefile.am | 4 ++++ src/irc.cpp | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Makefile.am b/Makefile.am index d3d9ccc..3d7481d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/src/irc.cpp b/src/irc.cpp index dea4e3b..b726126 100644 --- a/src/irc.cpp +++ b/src/irc.cpp @@ -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(); -- 2.56.0