performance: improve ossl_lh_strcasehash
authorPauli <pauli@openssl.org>
Fri, 20 May 2022 00:15:55 +0000 (10:15 +1000)
committerDmitry Belyavskiy <beldmit@gmail.com>
Sat, 21 May 2022 19:53:39 +0000 (21:53 +0200)
This improvement seems to roughly halve the time it takes to run the
ossl_lh_strcasehash function.

It should have no impact on the strings we hash and search for often (algorithm
names, property strings).

Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18354)

crypto/lhash/lhash.c

index 21757e47cc08ca2138a93e4efb697e8175eb35d3..a652631e10d0dc770116eb609b842642a462e417 100644 (file)
@@ -344,18 +344,37 @@ unsigned long OPENSSL_LH_strhash(const char *c)
     return (ret >> 16) ^ ret;
 }
 
+/*
+ * Case insensitive string hashing.
+ *
+ * The lower/upper case bit is masked out (forcing all letters to be capitals).
+ * The major side effect on non-alpha characters is mapping the symbols and
+ * digits into the control character range (which should be harmless).
+ * The duplication (with respect to the hash value) of printable characters
+ * are that '`', '{', '|', '}' and '~' map to '@', '[', '\', ']' and '^'
+ * respectively (which seems tolerable).
+ *
+ * For EBCDIC, the alpha mapping is to lower case, most symbols go to control
+ * characters.  The only duplication is '0' mapping to '^', which is better
+ * than for ASCII.
+ */
 unsigned long ossl_lh_strcasehash(const char *c)
 {
     unsigned long ret = 0;
     long n;
     unsigned long v;
     int r;
+#if defined(CHARSET_EBCDIC) && !defined(CHARSET_EBCDIC_TEST)
+    const long int case_adjust = ~0x40;
+#else
+    const long int case_adjust = ~0x20;
+#endif
 
     if (c == NULL || *c == '\0')
         return ret;
 
     for (n = 0x100; *c != '\0'; n += 0x100) {
-        v = n | ossl_tolower(*c);
+        v = n | (case_adjust & *c);
         r = (int)((v >> 2) ^ v) & 0x0f;
         /* cast to uint64_t to avoid 32 bit shift of 32 bit value */
         ret = (ret << r) | (unsigned long)((uint64_t)ret >> (32 - r));