]> Savannah Git Hosting - gnulib.git/commitdiff
Tune single-byte code involving tolower
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 27 Aug 2023 06:19:10 +0000 (23:19 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 27 Aug 2023 06:34:01 +0000 (23:34 -0700)
* lib/mbmemcasecmp.c (mbmemcasecmp):
* lib/mbscasecmp.c (mbscasecmp):
* lib/mbscasestr.c (mbscasestr):
* lib/mbsncasecmp.c (mbsncasecmp):
* lib/mbspcasecmp.c (mbspcasecmp):
Avoid some unnecessary calls to tolower.  For example, if the two
single-byte characters are equal before downcasing there is no
need to call tolower on either character.

ChangeLog
lib/mbmemcasecmp.c
lib/mbscasecmp.c
lib/mbscasestr.c
lib/mbsncasecmp.c
lib/mbspcasecmp.c

index ff09eed9ba300b09c67a0c6e50af0645e6f9b393..de52b57755eeeaeacda1c6f07a6c154c1dffe1d5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2023-08-26  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Tune single-byte code involving tolower
+       * lib/mbmemcasecmp.c (mbmemcasecmp):
+       * lib/mbscasecmp.c (mbscasecmp):
+       * lib/mbscasestr.c (mbscasestr):
+       * lib/mbsncasecmp.c (mbsncasecmp):
+       * lib/mbspcasecmp.c (mbspcasecmp):
+       Avoid some unnecessary calls to tolower.  For example, if the two
+       single-byte characters are equal before downcasing there is no
+       need to call tolower on either character.
+
 2023-08-26  Bruno Haible  <bruno@clisp.org>
 
        c32width tests: Avoid failure on FreeBSD 12.
index f4a397033e7b1fdffe04c17943b88c6b88871516..2bf4effa479d693edb5fe5c78e95f323110981b0 100644 (file)
@@ -33,19 +33,18 @@ mbmemcasecmp (const char *s1, size_t n1, const char *s2, size_t n2)
   if (s1 == s2)
     return _GL_CMP (n1, n2);
 
+  const char *iter1 = s1;
+  const char *iter2 = s2;
+
   if (MB_CUR_MAX > 1)
     {
       const char *s1_end = s1 + n1;
       mbif_state_t state1;
-      const char *iter1;
       mbif_init (state1);
-      iter1 = s1;
 
       const char *s2_end = s2 + n2;
       mbif_state_t state2;
-      const char *iter2;
       mbif_init (state2);
-      iter2 = s2;
 
       while (mbif_avail (state1, iter1, s1_end)
              && mbif_avail (state2, iter2, s2_end))
@@ -70,32 +69,33 @@ mbmemcasecmp (const char *s1, size_t n1, const char *s2, size_t n2)
     }
   else
     {
-      const unsigned char *s1_end = (const unsigned char *) (s1 + n1);
-      const unsigned char *s2_end = (const unsigned char *) (s2 + n2);
-      const unsigned char *p1 = (const unsigned char *) s1;
-      const unsigned char *p2 = (const unsigned char *) s2;
+      const char *s1_end = s1 + n1;
+      const char *s2_end = s2 + n2;
 
-      while (p1 < s1_end && p2 < s2_end)
+      while (iter1 < s1_end && iter2 < s2_end)
         {
-          unsigned char c1 = tolower (*p1);
-          unsigned char c2 = tolower (*p2);
-          if (c1 != c2)
+          unsigned char c1 = *iter1++;
+          unsigned char c2 = *iter2++;
+          /* On machines where 'char' and 'int' are types of the same size,
+             the difference of two 'unsigned char' values - including
+             the sign bit - doesn't fit in an 'int'.  */
+          int cmp = UCHAR_MAX <= INT_MAX ? c1 - c2 : _GL_CMP (c1, c2);
+          if (cmp != 0)
             {
-              if (UCHAR_MAX <= INT_MAX)
-                return c1 - c2;
-              else
-                /* On machines where 'char' and 'int' are types of the same
-                   size, the difference of two 'unsigned char' values
-                   - including the sign bit - doesn't fit in an 'int'.  */
-                return _GL_CMP (c1, c2);
+              c1 = tolower (c1);
+              if (c1 != c2)
+                {
+                  c2 = tolower (c2);
+                  cmp = UCHAR_MAX <= INT_MAX ? c1 - c2 : _GL_CMP (c1, c2);
+                  if (cmp != 0)
+                    return cmp;
+                }
             }
-          ++p1;
-          ++p2;
         }
-      if (p1 < s1_end)
+      if (iter1 < s1_end)
         /* s2 terminated before s1.  */
         return 1;
-      if (p2 < s2_end)
+      if (iter2 < s2_end)
         /* s1 terminated before s2.  */
         return -1;
       return 0;
index 3a20cb7f3ff696a99712a36fd08f5b79e4c84094..80dc18529d7d3be0931ea4894516153aadcfeebc 100644 (file)
@@ -37,20 +37,19 @@ mbscasecmp (const char *s1, const char *s2)
   if (s1 == s2)
     return 0;
 
+  const char *iter1 = s1;
+  const char *iter2 = s2;
+
   /* Be careful not to look at the entire extent of s1 or s2 until needed.
      This is useful because when two strings differ, the difference is
      most often already in the very few first characters.  */
   if (MB_CUR_MAX > 1)
     {
       mbuif_state_t state1;
-      const char *iter1;
       mbuif_init (state1);
-      iter1 = s1;
 
       mbuif_state_t state2;
-      const char *iter2;
       mbuif_init (state2);
-      iter2 = s2;
 
       while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
         {
@@ -73,30 +72,26 @@ mbscasecmp (const char *s1, const char *s2)
       return 0;
     }
   else
-    {
-      const unsigned char *p1 = (const unsigned char *) s1;
-      const unsigned char *p2 = (const unsigned char *) s2;
-      unsigned char c1, c2;
-
-      do
-        {
-          c1 = tolower (*p1);
-          c2 = tolower (*p2);
-
-          if (c1 == '\0')
-            break;
-
-          ++p1;
-          ++p2;
-        }
-      while (c1 == c2);
-
-      if (UCHAR_MAX <= INT_MAX)
-        return c1 - c2;
-      else
+    for (;;)
+      {
+        unsigned char c1 = *iter1++;
+        unsigned char c2 = *iter2++;
         /* On machines where 'char' and 'int' are types of the same size, the
            difference of two 'unsigned char' values - including the sign bit -
            doesn't fit in an 'int'.  */
-        return _GL_CMP (c1, c2);
-    }
+        int cmp = UCHAR_MAX <= INT_MAX ? c1 - c2 : _GL_CMP (c1, c2);
+        if (cmp != 0)
+          {
+            c1 = tolower (c1);
+            if (c1 == c2)
+              cmp = 0;
+            else
+              {
+                c2 = tolower (c2);
+                cmp = UCHAR_MAX <= INT_MAX ? c1 - c2 : _GL_CMP (c1, c2);
+              }
+          }
+        if (cmp | !c1)
+          return cmp;
+      }
 }
index 6946fff21cb7cd43266b37d45337f348c9eabfa0..d2b439f1e1ee5ab68f38f4bd8e97cdd784a7c690 100644 (file)
@@ -337,8 +337,9 @@ mbscasestr (const char *haystack, const char *needle)
           const char *needle_last_ccount = needle; /* = needle + last_ccount */
 
           /* Speed up the following searches of needle by caching its first
-             character.  */
-          unsigned char b = tolower ((unsigned char) *needle);
+             character and lowercase counterpart.  */
+          unsigned char B = *needle;
+          unsigned char b = tolower (B);
 
           needle++;
           for (;; haystack++)
@@ -381,7 +382,8 @@ mbscasestr (const char *haystack, const char *needle)
 
               outer_loop_count++;
               comparison_count++;
-              if (tolower ((unsigned char) *haystack) == b)
+              unsigned char H = *haystack;
+              if (H == B || H == b || tolower (H) == b)
                 /* The first character matches.  */
                 {
                   const char *rhaystack = haystack + 1;
@@ -396,8 +398,9 @@ mbscasestr (const char *haystack, const char *needle)
                         /* No match.  */
                         return NULL;
                       comparison_count++;
-                      if (tolower ((unsigned char) *rhaystack)
-                          != tolower ((unsigned char) *rneedle))
+                      if (! (*rhaystack == *rneedle
+                             || (tolower ((unsigned char) *rhaystack)
+                                 == tolower ((unsigned char) *rneedle))))
                         /* Nothing in this round.  */
                         break;
                     }
index 0b7027d91d934de29016ea36ec27083c52c5e9d5..8ee1df7d4d25dcdeefcbb58e1fb233ca74676668 100644 (file)
@@ -39,20 +39,19 @@ mbsncasecmp (const char *s1, const char *s2, size_t n)
   if (s1 == s2 || n == 0)
     return 0;
 
+  const char *iter1 = s1;
+  const char *iter2 = s2;
+
   /* Be careful not to look at the entire extent of s1 or s2 until needed.
      This is useful because when two strings differ, the difference is
      most often already in the very few first characters.  */
   if (MB_CUR_MAX > 1)
     {
       mbuif_state_t state1;
-      const char *iter1;
       mbuif_init (state1);
-      iter1 = s1;
 
       mbuif_state_t state2;
-      const char *iter2;
       mbuif_init (state2);
-      iter2 = s2;
 
       while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
         {
@@ -78,26 +77,26 @@ mbsncasecmp (const char *s1, const char *s2, size_t n)
       return 0;
     }
   else
-    {
-      const unsigned char *p1 = (const unsigned char *) s1;
-      const unsigned char *p2 = (const unsigned char *) s2;
-      unsigned char c1, c2;
-
-      for (; ; p1++, p2++)
-        {
-          c1 = tolower (*p1);
-          c2 = tolower (*p2);
-
-          if (--n == 0 || c1 == '\0' || c1 != c2)
-            break;
-        }
-
-      if (UCHAR_MAX <= INT_MAX)
-        return c1 - c2;
-      else
+    for (;;)
+      {
+        unsigned char c1 = *iter1++;
+        unsigned char c2 = *iter2++;
         /* On machines where 'char' and 'int' are types of the same size, the
            difference of two 'unsigned char' values - including the sign bit -
            doesn't fit in an 'int'.  */
-        return _GL_CMP (c1, c2);
-    }
+        int cmp = UCHAR_MAX <= INT_MAX ? c1 - c2 : _GL_CMP (c1, c2);
+        if (cmp != 0)
+          {
+            c1 = tolower (c1);
+            if (c1 == c2)
+              cmp = 0;
+            else
+              {
+                c2 = tolower (c2);
+                cmp = UCHAR_MAX <= INT_MAX ? c1 - c2 : _GL_CMP (c1, c2);
+              }
+          }
+        if (cmp | !c1 | !--n)
+          return cmp;
+      }
 }
index daec2ffda383434173baf4300a0c7b16c1029254..090d12531bf55350feceda88b4cd1150cb22e4a3 100644 (file)
@@ -39,20 +39,19 @@ mbspcasecmp (const char *string, const char *prefix)
   if (string == prefix)
     return (char *) (string + strlen (string));
 
+  const char *iter1 = string;
+  const char *iter2 = prefix;
+
   /* Be careful not to look at the entire extent of STRING or PREFIX until
      needed.  This is useful because when two strings differ, the difference is
      most often already in the very few first characters.  */
   if (MB_CUR_MAX > 1)
     {
       mbuif_state_t state1;
-      const char *iter1;
       mbuif_init (state1);
-      iter1 = string;
 
       mbuif_state_t state2;
-      const char *iter2;
       mbuif_init (state2);
-      iter2 = prefix;
 
       while (mbuif_avail (state1, iter1) && mbuif_avail (state2, iter2))
         {
@@ -74,25 +73,23 @@ mbspcasecmp (const char *string, const char *prefix)
         return NULL;
     }
   else
-    {
-      const unsigned char *p1 = (const unsigned char *) string;
-      const unsigned char *p2 = (const unsigned char *) prefix;
-      unsigned char c1, c2;
-
-      for (; ; p1++, p2++)
-        {
-          c1 = tolower (*p1);
-          c2 = tolower (*p2);
-
-          if (c2 == '\0' || c1 != c2)
-            break;
-        }
-
-      if (c2 == '\0')
-        /* PREFIX equals STRING or is terminated before STRING.  */
-        return (char *) p1;
-      else
-        /* STRING terminated before PREFIX.  */
-        return NULL;
-    }
+    for (;; iter1++, iter2++)
+      {
+        unsigned char c2 = *iter2;
+
+        if (c2 == '\0')
+          /* PREFIX equals STRING or is terminated before STRING.  */
+          return (char *) iter1;
+
+        unsigned char c1 = *iter1;
+
+        if (c1 != c2)
+          {
+            c1 = tolower (c1);
+            if (c1 != c2 && c1 != tolower (c2))
+              /* STRING and PREFIX disagree,
+                 or STRING terminated before PREFIX.  */
+              return NULL;
+          }
+      }
 }