From bb8ec5eb650678ca75e23b23729f25fc10825923 Mon Sep 17 00:00:00 2001 From: Ron Kuper Date: Tue, 25 Aug 2026 12:12:35 -0400 Subject: [PATCH] strcase: inline the raw case conversions Curl_raw_toupper() and Curl_raw_tolower() were out-of-line functions doing a single table lookup, and casecompare() invokes one of them twice per byte compared, so every case-insensitive comparison in the library paid two calls per byte: header matching, scheme and host compares, cookie domains. Make them static CURL_INLINE functions in strcase.h and give the two mapping tables external linkage so the lookup inlines in every translation unit without relying on LTO or unity mode. The tables and the mapping they perform are unchanged, so this is not a behavior change. curl_strequal() on identical header names: -49% on a Cortex-A55, -51% on a 250MHz e300c3. Closes #22672 --- lib/strcase.c | 18 ++---------------- lib/strcase.h | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/strcase.c b/lib/strcase.c index 9f70f41bd6..6c3597cc37 100644 --- a/lib/strcase.c +++ b/lib/strcase.c @@ -26,7 +26,7 @@ #include "strcase.h" /* Mapping table to go from lowercase to uppercase for plain ASCII.*/ -static const unsigned char touppermap[256] = { +const unsigned char Curl_touppermap[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, @@ -48,7 +48,7 @@ static const unsigned char touppermap[256] = { }; /* Mapping table to go from uppercase to lowercase for plain ASCII.*/ -static const unsigned char tolowermap[256] = { +const unsigned char Curl_tolowermap[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, @@ -69,20 +69,6 @@ static const unsigned char tolowermap[256] = { 255 }; -/* Portable, consistent toupper. Do not use toupper() because its behavior is - altered by the current locale. */ -char Curl_raw_toupper(char in) -{ - return (char)touppermap[(unsigned char)in]; -} - -/* Portable, consistent tolower. Do not use tolower() because its behavior is - altered by the current locale. */ -char Curl_raw_tolower(char in) -{ - return (char)tolowermap[(unsigned char)in]; -} - /* Copy an upper case version of the string from src to dest. The * strings may overlap. No more than n characters of the string are copied * (including any NUL) and the destination string will NOT be diff --git a/lib/strcase.h b/lib/strcase.h index 54299812be..559db875bd 100644 --- a/lib/strcase.h +++ b/lib/strcase.h @@ -25,8 +25,24 @@ ***************************************************************************/ #include "curl_setup.h" -char Curl_raw_toupper(char in); -char Curl_raw_tolower(char in); +/* Mapping tables for plain ASCII case conversion, defined in strcase.c. + Declared here so the conversions below inline at every call site without + relying on LTO or a unity build: casecompare() invokes one of them twice + per byte compared, where the call costs more than the lookup itself. */ +extern const unsigned char Curl_touppermap[256]; +extern const unsigned char Curl_tolowermap[256]; + +/* Portable, consistent toupper/tolower. Do not use toupper()/tolower() from + , whose behavior is altered by the current locale. */ +static CURL_INLINE char Curl_raw_toupper(char in) +{ + return (char)Curl_touppermap[(unsigned char)in]; +} + +static CURL_INLINE char Curl_raw_tolower(char in) +{ + return (char)Curl_tolowermap[(unsigned char)in]; +} /* checkprefix() is a shorter version of the above, used when the first argument is the string literal */