[glib: 1/3] Optimize g_str_has_*() functions to detect const arguments at compile-time




commit bbd3ad8c0069a44f84590a8f53e89c2c3f910c3e
Author: Emmanuel Fleury <emmanuel fleury gmail com>
Date:   Fri Aug 19 18:00:19 2022 +0200

    Optimize g_str_has_*() functions to  detect const arguments at compile-time
    
    Compilers can emit optimized code for str|strn|mem)cmp(str,"literal")
    at compile-time. This commit use the preprocessor to introduce this
    kind of optimization for the functions g_str_has_prefix() and
    g_str_has_suffix().
    
    Original work by Ben @bdejean
    
    Closes issue #24

 glib/gstrfuncs.c | 10 ++++------
 glib/gstrfuncs.h | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 48 insertions(+), 11 deletions(-)
---
diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c
index ee934e5d76..3030114e33 100644
--- a/glib/gstrfuncs.c
+++ b/glib/gstrfuncs.c
@@ -2928,9 +2928,8 @@ g_strrstr_len (const gchar *haystack,
  *
  * Since: 2.2
  */
-gboolean
-g_str_has_suffix (const gchar *str,
-                  const gchar *suffix)
+gboolean (g_str_has_suffix) (const gchar *str,
+                             const gchar *suffix)
 {
   gsize str_len;
   gsize suffix_len;
@@ -2958,9 +2957,8 @@ g_str_has_suffix (const gchar *str,
  *
  * Since: 2.2
  */
-gboolean
-g_str_has_prefix (const gchar *str,
-                  const gchar *prefix)
+gboolean (g_str_has_prefix) (const gchar *str,
+                             const gchar *prefix)
 {
   g_return_val_if_fail (str != NULL, FALSE);
   g_return_val_if_fail (prefix != NULL, FALSE);
diff --git a/glib/gstrfuncs.h b/glib/gstrfuncs.h
index 3c1dc45ecb..8c2f59cf50 100644
--- a/glib/gstrfuncs.h
+++ b/glib/gstrfuncs.h
@@ -33,6 +33,7 @@
 
 #include <stdarg.h>
 #include <string.h>
+
 #include <glib/gmacros.h>
 #include <glib/gtypes.h>
 #include <glib/gerror.h>
@@ -139,11 +140,49 @@ gchar *               g_strrstr_len    (const gchar  *haystack,
                                        const gchar  *needle);
 
 GLIB_AVAILABLE_IN_ALL
-gboolean              g_str_has_suffix (const gchar  *str,
-                                       const gchar  *suffix);
-GLIB_AVAILABLE_IN_ALL
-gboolean              g_str_has_prefix (const gchar  *str,
-                                       const gchar  *prefix);
+gboolean             (g_str_has_suffix) (const gchar *str,
+                                         const gchar *suffix);
+GLIB_AVAILABLE_IN_ALL
+gboolean             (g_str_has_prefix) (const gchar *str,
+                                         const gchar *prefix);
+
+#if G_GNUC_CHECK_VERSION (2, 0)
+
+/* A note on the 'x + !x' terms: These are added to workaround a false
+ * warning in gcc 10< which is ignoring the check 'x != NULL' that is
+ * set outside of the G_GNUC_EXTENSION scope. Without 'x + !x' it
+ * would complain that x may be NULL where strlen() and memcmp()
+ * both require non-null arguments. */
+
+#define g_str_has_prefix(STR, PREFIX)                                   \
+  ((STR != NULL && PREFIX != NULL && __builtin_constant_p (PREFIX)) ?   \
+   G_GNUC_EXTENSION ({                                                  \
+       const char *const __str = STR;                                   \
+       const char *const __prefix = PREFIX;                             \
+       const size_t __str_len = strlen (__str + !__str);                \
+       const size_t __prefix_len = strlen (__prefix + !__prefix);       \
+       (__str_len >= __prefix_len) ?                                    \
+         memcmp (__str + !__str,                                        \
+                 __prefix + !__prefix, __prefix_len) == 0 : FALSE;      \
+     })                                                                 \
+   :                                                                    \
+   (g_str_has_prefix) (STR, PREFIX))
+
+#define g_str_has_suffix(STR, SUFFIX)                                   \
+  ((STR != NULL && SUFFIX != NULL && __builtin_constant_p (SUFFIX)) ?   \
+   G_GNUC_EXTENSION ({                                                  \
+       const char *const __str = STR;                                   \
+       const char *const __suffix = SUFFIX;                             \
+       const size_t __str_len = strlen (__str + !__str);                \
+       const size_t __suffix_len = strlen (__suffix + !__suffix);       \
+       (__str_len >= __suffix_len) ?                                    \
+         memcmp (__str + !__str + __str_len - __suffix_len,             \
+                 __suffix + !__suffix, __suffix_len) == 0 : FALSE;      \
+     })                                                                 \
+   :                                                                    \
+   (g_str_has_suffix) (STR, SUFFIX))
+
+#endif /* G_GNUC_CHECK_VERSION (2, 0) */
 
 /* String to/from double conversion functions */
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]