On Wed, 2025-03-12 at 19:55 +0300, Alexander Borisov wrote: > 1. Added static for casemap() function. Otherwise the compiler could > not > optimize the code and the performance dropped significantly.
Oops, it was static, but I made it external just to see what code it generated. I didn't intend to publish it as an external function -- thank you for catching that! > 2. Added a fast path for codepoint < 0x80. > > v3j-0002: > In the fast path for codepoints < 0x80, I added a premature return. > This avoided additional insertions, which increased performance. What do you mean "additional insertions"? Also, should we just compute the results in the fast path? We don't even need a table. Rough patch attached to go on top of v4-0001. Should we properly return CASEMAP_SELF when *simple == u1, or is it ok to return CASEMAP_SIMPLE? It probably doesn't matter performance-wise, but it feels more correct to return CASEMAP_SELF. > > Perhaps for general > beauty it should be made static inline, I don't have a rigid position > here. We ordinarily use "static inline" if it's in a header file, and "static" if it's in a .c file, so I'll do it that way. > I was purely based on existing approaches in Postgres, the > Normalization Forms have them separated into different headers. Just > trying to be consistent with existing approaches. I think that was done for normalization primarily because it's not used #ifndef FRONTEND (see unicode_norm.c), and perhaps also because it's just a more complex function worthy of its own file. I looked into the history, and commit 783f0cc64d explains why perfect hashing is not used in the frontend: "The decomposition table remains the same, getting used for the binary search in the frontend code, where we care more about the size of the libraries like libpq over performance..." > Regards, Jeff Davis
From ed4d2803aa32add7c05726286b94e78e49bb1257 Mon Sep 17 00:00:00 2001 From: Jeff Davis <j...@j-davis.com> Date: Wed, 12 Mar 2025 11:56:59 -0700 Subject: [PATCH vtmp] fastpath --- src/common/unicode_case.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/common/unicode_case.c b/src/common/unicode_case.c index 2b3b4cdc2e7..b1fc1651043 100644 --- a/src/common/unicode_case.c +++ b/src/common/unicode_case.c @@ -390,11 +390,41 @@ casemap(pg_wchar u1, CaseKind casekind, bool full, { const pg_case_map *map; + /* + * Fast path for early codepoints. The only interesting characters are + * [a-zA-Z]. + */ if (u1 < 0x80) { - *simple = case_map[u1].simplemap[casekind]; + /* fast-path codepoints do not have special casing */ + Assert(find_case_map(u1)->special_case == NULL); - return CASEMAP_SIMPLE; + switch (casekind) + { + case CaseLower: + case CaseFold: + if (u1 >= 'A' && u1 <= 'Z') + { + *simple = u1 + 0x20; + Assert(case_map[u1].simplemap[casekind] == *simple); + return CASEMAP_SIMPLE; + } + break; + case CaseTitle: + case CaseUpper: + if (u1 >= 'a' && u1 <= 'z') + { + *simple = u1 - 0x20; + Assert(case_map[u1].simplemap[casekind] == *simple); + return CASEMAP_SIMPLE; + } + break; + default: + Assert(false); + } + + Assert(case_map[u1].simplemap[casekind] == u1); + return CASEMAP_SELF; } map = find_case_map(u1); -- 2.34.1