From bbd3ad8c0069a44f84590a8f53e89c2c3f910c3e Mon Sep 17 00:00:00 2001 From: Emmanuel Fleury Date: Fri, 19 Aug 2022 18:00:19 +0200 Subject: [PATCH] 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 | 47 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index ee934e5d7..3030114e3 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 3c1dc45ec..8c2f59cf5 100644 --- a/glib/gstrfuncs.h +++ b/glib/gstrfuncs.h @@ -33,6 +33,7 @@ #include #include + #include #include #include @@ -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); +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_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 */