Cleanup and augment string handling based on https://github.com/mono/mono/pull/15522.
authorJay Krell <jaykrell@microsoft.com>
Wed, 3 Jul 2019 02:55:10 +0000 (19:55 -0700)
committerLarry Ewing <lewing@microsoft.com>
Wed, 4 Sep 2019 03:46:10 +0000 (22:46 -0500)
1. When comparing strings, check pointer equality.
Faster when they match, slower when they do not.

2. Provide string lowercasing into a provided buffer, which can equal
the input, to avoid extra malloc/free.

3. define G_STRING_CONSTANT_AND_LENGTH(x) (x), G_N_ELEMENTS (x) - 1
e.g. strncmp (foo, G_STRING_CONSTANT_AND_LENGTH ("version"))

Commit migrated from https://github.com/mono/mono/commit/8c288f06664c65050b153da0a8952209adc958a0

src/mono/mono/eglib/eglib-remap.h
src/mono/mono/eglib/glib.h
src/mono/mono/eglib/gstr.c

index 43d6543..0bbbcab 100644 (file)
@@ -16,6 +16,7 @@
 #define g_array_set_size monoeg_g_array_set_size
 #define g_array_sized_new monoeg_g_array_sized_new
 #define g_ascii_strdown monoeg_g_ascii_strdown
+#define g_ascii_strdown_no_alloc monoeg_g_ascii_strdown_no_alloc
 #define g_ascii_strncasecmp monoeg_g_ascii_strncasecmp
 #define g_ascii_tolower monoeg_g_ascii_tolower
 #define g_ascii_xdigit_value monoeg_g_ascii_xdigit_value
index 01dc664..2fc5fb9 100644 (file)
@@ -212,6 +212,9 @@ typedef guint32 gunichar;
  */
 #define G_N_ELEMENTS(s)      (sizeof(s) / sizeof ((s) [0]))
 
+// e.g. strncmp (foo, G_STRING_CONSTANT_AND_LENGTH ("version"))
+#define G_STRING_CONSTANT_AND_LENGTH(x) (x), G_N_ELEMENTS (x) - 1
+
 #define FALSE                0
 #define TRUE                 1
 
@@ -400,6 +403,7 @@ gchar  *g_stpcpy             (gchar *dest, const char *src);
 gchar   g_ascii_tolower      (gchar c);
 gchar   g_ascii_toupper      (gchar c);
 gchar  *g_ascii_strdown      (const gchar *str, gssize len);
+void    g_ascii_strdown_no_alloc (char* dst, const char* src, gsize len);
 gchar  *g_ascii_strup        (const gchar *str, gssize len);
 gint    g_ascii_strncasecmp  (const gchar *s1, const gchar *s2, gsize n);
 gint    g_ascii_strcasecmp   (const gchar *s1, const gchar *s2);
index 758aeb0..f028501 100644 (file)
@@ -821,11 +821,20 @@ g_ascii_tolower (gchar c)
        return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
 }
 
+void
+g_ascii_strdown_no_alloc (char* dst, const char* src, gsize len)
+{
+       // dst can equal src. no_alloc means this function does no
+       // allocation; caller may very well.
+
+       for (gsize i = 0; i < len; ++i)
+               dst [i] = g_ascii_tolower (src [i]);
+}
+
 gchar *
 g_ascii_strdown (const gchar *str, gssize len)
 {
        char *ret;
-       int i;
        
        g_return_val_if_fail  (str != NULL, NULL);
 
@@ -833,9 +842,8 @@ g_ascii_strdown (const gchar *str, gssize len)
                len = strlen (str);
        
        ret = g_malloc (len + 1);
-       for (i = 0; i < len; i++)
-               ret [i] = (guchar) g_ascii_tolower (str [i]);
-       ret [i] = 0;
+       g_ascii_strdown_no_alloc (ret, str, len);
+       ret [len] = 0;
        
        return ret;
 }
@@ -859,26 +867,50 @@ g_ascii_strup (const gchar *str, gssize len)
        
        ret = g_malloc (len + 1);
        for (i = 0; i < len; i++)
-               ret [i] = (guchar) g_ascii_toupper (str [i]);
+               ret [i] = g_ascii_toupper (str [i]);
        ret [i] = 0;
        
        return ret;
 }
 
+static
+int
+g_ascii_charcmp (char c1, char c2)
+{
+       // Do not subtract, to avoid overflow.
+       // Use unsigned to mimic strcmp, and so
+       // shorter strings compare as less.
+
+       const guchar u1 = (guchar)c1;
+       const guchar u2 = (guchar)c2;
+       return (u1 < u2) ? -1 : (u1 > u2) ? 1 : 0;
+}
+
+static
+int
+g_ascii_charcasecmp (char c1, char c2)
+{
+       return g_ascii_charcmp (g_ascii_tolower (c1), g_ascii_tolower (c2));
+}
+
 gint
 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
 {
+       // Unlike strncmp etc. this function does not stop at nul,
+       // unless there is a mismatch.
+
+       if (s1 == s2)
+               return 0;
+
        gsize i;
-       
+
        g_return_val_if_fail (s1 != NULL, 0);
        g_return_val_if_fail (s2 != NULL, 0);
 
        for (i = 0; i < n; i++) {
-               gchar c1 = g_ascii_tolower (*s1++);
-               gchar c2 = g_ascii_tolower (*s2++);
-               
-               if (c1 != c2)
-                       return c1 - c2;
+               const int j = g_ascii_charcasecmp (*s1++, *s2++);
+               if (j)
+                       return j;
        }
        
        return 0;
@@ -887,21 +919,22 @@ g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
 gint
 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
 {
-       const char *sp1 = s1;
-       const char *sp2 = s2;
-       
+       if (s1 == s2)
+               return 0;
+
        g_return_val_if_fail (s1 != NULL, 0);
        g_return_val_if_fail (s2 != NULL, 0);
-       
-       while (*sp1 != '\0') {
-               char c1 = g_ascii_tolower (*sp1++);
-               char c2 = g_ascii_tolower (*sp2++);
-               
-               if (c1 != c2)
-                       return c1 - c2;
+
+       char c1;
+
+       while ((c1 = *s1)) {
+               ++s1;
+               const int j = g_ascii_charcasecmp (c1, *s2++);
+               if (j)
+                       return j;
        }
-       
-       return (*sp1) - (*sp2);
+
+       return g_ascii_charcmp (0, *s2);
 }
 
 gboolean