[glib] macros: add support for GNUC cleanup __attribute__



commit 2596919c58a364243196e65a9adda693448139f7
Author: Ryan Lortie <desrt desrt ca>
Date:   Wed Jan 28 11:27:35 2015 +0000

    macros: add support for GNUC cleanup __attribute__
    
    Add g_auto() and g_autoptr() as helpers for declaring variables with
    automatic cleanup.
    
    Add some macros to help types define cleanup functions for themselves.
    
    Going forward it will be an expectation that people use this macro when
    creating a new type, even if they do not intend to use the auto-cleanup
    functionality for themselves.
    
    These new macros only work on GCC and clang, which is why we resisted
    adding them for so long.  There exist many people who are only
    interested in writing programs for these compilers, however, and a
    similar API in libgsystem has proven to be extremely popular, so let's
    expose this functionality to an even wider audience.
    
    We ignore deprecation warnings when emitting the free functions, which
    seems suspicious.  The reason that we do this is not because we want to
    call deprecated functions, but just the opposite: sometimes the free
    function will be an _unref() function that is only AVAILABLE_IN newer
    versions, and these warnings are also implemented as deprecation
    warnings.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=743640

 docs/reference/glib/glib-sections.txt |    7 ++
 glib/docs.c                           |  190 +++++++++++++++++++++++++++++++++
 glib/gmacros.h                        |   34 ++++++
 3 files changed, 231 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 53b7732..f48c2f0 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -363,6 +363,13 @@ G_LOG_2_BASE_10
 G_INLINE_FUNC
 
 <SUBSECTION>
+g_auto
+g_autoptr
+G_DEFINE_AUTOPTR_CLEANUP_FUNC
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC
+
+<SUBSECTION>
 G_STMT_START
 G_STMT_END
 
diff --git a/glib/docs.c b/glib/docs.c
index 43c9f27..d681165 100644
--- a/glib/docs.c
+++ b/glib/docs.c
@@ -2310,6 +2310,196 @@
  * Defined to 1 if gcc-style visibility handling is supported.
  */
 
+/* g_auto(), g_autoptr() and helpers {{{1 */
+
+/**
+ * g_auto:
+ * @typename: a supported variable type
+ *
+ * Helper to declare a variable with automatic cleanup.
+ *
+ * The variable is cleaned up in a way appropriate to its type when the
+ * variable goes out of scope.  The type must support this.
+ *
+ * This feature is only supported on GCC and clang.  This macro is not
+ * defined on other compilers and should not be used in programs that
+ * are intended to be portable to those compilers.
+ *
+ * This is meant to be used with stack-allocated structures and
+ * non-pointer types.  For the (more commonly used) pointer version, see
+ * g_autoptr().
+ *
+ * This macro can be used to avoid having to do explicit cleanups of
+ * local variables when exiting functions.  It often vastly simplifies
+ * handling of error conditions, removing the need for various tricks
+ * such as 'goto out' or repeating of cleanup code.  It is also helpful
+ * for non-error cases.
+ *
+ * Consider the following example:
+ *
+ * |[
+ * GVariant *
+ * my_func(void)
+ * {
+ *   g_auto(GQueue) queue = G_QUEUE_INIT;
+ *   g_auto(GVariantBuilder) builder;
+ *
+ *   g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+ *
+ *   ...
+ *
+ *   if (error_condition)
+ *     return NULL;
+ *
+ *   ...
+ *
+ *   return g_variant_builder_end (&builder);
+ * }
+ * ]|
+ *
+ * You must initialise the variable in some way -- either by use of an
+ * initialiser or by ensuring that an _init function will be called on
+ * it unconditionally before it goes out of scope.
+ *
+ * Since: 2.44
+ */
+
+/**
+ * g_autoptr:
+ * @typename: a supported variable type
+ *
+ * Helper to declare a pointer variable with automatic cleanup.
+ *
+ * The variable is cleaned up in a way appropriate to its type when the
+ * variable goes out of scope.  The type must support this.
+ *
+ * This feature is only supported on GCC and clang.  This macro is not
+ * defined on other compilers and should not be used in programs that
+ * are intended to be portable to those compilers.
+ *
+ * This is meant to be used to declare pointers to types with cleanup
+ * functions.  The type of the variable is a pointer to @typename.  You
+ * must not add your own '*'.
+ *
+ * This macro can be used to avoid having to do explicit cleanups of
+ * local variables when exiting functions.  It often vastly simplifies
+ * handling of error conditions, removing the need for various tricks
+ * such as 'goto out' or repeating of cleanup code.  It is also helpful
+ * for non-error cases.
+ *
+ * Consider the following example:
+ *
+ * |[
+ * gboolean
+ * check_exists(GVariant *dict)
+ * {
+ *   g_autoptr(GVariant) dirname;
+ *   g_autoptr(GVariant) basename = NULL;
+ *   g_autoptr(gchar) path = NULL;
+ *
+ *   dirname = g_variant_lookup_value (dict, "dirname", G_VARIANT_TYPE_STRING);
+ *
+ *   if (dirname == NULL)
+ *     return FALSE;
+ *
+ *   basename = g_variant_lookup_value (dict, "basename", G_VARIANT_TYPE_STRING);
+ *
+ *   if (basename == NULL)
+ *     return FALSE;
+ *
+ *   path = g_build_filename (g_variant_get_string (dirname, NULL),
+ *                            g_variant_get_string (basename, NULL),
+ *                            NULL);
+ *
+ *   return g_access (path, R_OK) == 0;
+ * }
+ * ]|
+ *
+ * You must initialise the variable in some way -- either by use of an
+ * initialiser or by ensuring that it is assigned to unconditionally
+ * before it goes out of scope.
+ *
+ * Since: 2.44
+ */
+
+/**
+ * G_DEFINE_AUTOPTR_CLEANUP_FUNC:
+ * @TypeName: a type name to define a g_autoptr() cleanup function for
+ * @func: the cleanup function
+ *
+ * Defines the appropriate cleanup function for a pointer type.
+ *
+ * The function will not be called if the variable to be cleaned up
+ * contains %NULL.
+ *
+ * This will typically be the _free() or _unref() function for the given
+ * type.
+ *
+ * With this definition, it will be possible to use g_autoptr() with
+ * @TypeName.
+ *
+ * |[
+ * G_DEFINE_AUTOPTR_CLEANUP_FUNC(GObject, g_object_unref)
+ * ]|
+ *
+ * This macro should be used unconditionally; it is a no-op on compilers
+ * where cleanup is not supported.
+ *
+ * Since: 2.44
+ */
+
+/**
+ * G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC:
+ * @TypeName: a type name to define a g_auto() cleanup function for
+ * @func: the clear function
+ *
+ * Defines the appropriate cleanup function for a type.
+ *
+ * This will typically be the _clear() function for the given type.
+ *
+ * With this definition, it will be possible to use g_auto() with
+ * @TypeName.
+ *
+ * |[
+ * G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear)
+ * ]|
+ *
+ * This macro should be used unconditionally; it is a no-op on compilers
+ * where cleanup is not supported.
+ *
+ * Since: 2.44
+ */
+
+/**
+ * G_DEFINE_AUTO_CLEANUP_FREE_FUNC:
+ * @TypeName: a type name to define a g_auto() cleanup function for
+ * @func: the free function
+ * @none: the "none" value for the type
+ *
+ * Defines the appropriate cleanup function for a type.
+ *
+ * With this definition, it will be possible to use g_auto() with
+ * @TypeName.
+ *
+ * This function will be rarely used.  It is used with pointer-based
+ * typedefs and non-pointer types where the value of the variable
+ * represents a resource that must be freed.  Two examples are #GStrv
+ * and file descriptors.
+ *
+ * @none specifies the "none" value for the type in question.  It is
+ * probably something like %NULL or -1.  If the variable is found to
+ * contain this value then the free function will not be called.
+ *
+ * |[
+ * G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL)
+ * ]|
+ *
+ * This macro should be used unconditionally; it is a no-op on compilers
+ * where cleanup is not supported.
+ *
+ * Since: 2.44
+ */
+
 /* Windows Compatibility Functions {{{1 */
 
 /**
diff --git a/glib/gmacros.h b/glib/gmacros.h
index 7320228..5b53bb5 100644
--- a/glib/gmacros.h
+++ b/glib/gmacros.h
@@ -373,4 +373,38 @@
 #define GLIB_UNAVAILABLE(maj,min) G_UNAVAILABLE(maj,min) _GLIB_EXTERN
 #endif
 
+#ifdef __GNUC__
+
+/* these macros are private */
+#define _GLIB_AUTOPTR_FUNC_NAME(TypeName) glib_autoptr_cleanup_##TypeName
+#define _GLIB_AUTOPTR_TYPENAME(TypeName)  TypeName##_autoptr
+#define _GLIB_AUTO_FUNC_NAME(TypeName)    glib_auto_cleanup_##TypeName
+#define _GLIB_CLEANUP(func)               __attribute__((cleanup(func)))
+
+/* these macros are API */
+#define G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func) \
+  typedef TypeName *_GLIB_AUTOPTR_TYPENAME(TypeName);                                                        
   \
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                                           
   \
+  static inline void _GLIB_AUTOPTR_FUNC_NAME(TypeName) (TypeName **_ptr) { if (*_ptr) (func) (*_ptr); }      
   \
+  G_GNUC_END_IGNORE_DEPRECATIONS
+#define G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func) \
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                                           
   \
+  static inline void _GLIB_AUTO_FUNC_NAME(TypeName) (TypeName *_ptr) { (func) (_ptr); }                      
   \
+  G_GNUC_END_IGNORE_DEPRECATIONS
+#define G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func, none) \
+  G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                                           
   \
+  static inline void _GLIB_AUTO_FUNC_NAME(TypeName) (TypeName *_ptr) { if (*_ptr != none) (func) (*_ptr); }  
   \
+  G_GNUC_END_IGNORE_DEPRECATIONS
+#define g_autoptr(TypeName) _GLIB_CLEANUP(_GLIB_AUTOPTR_FUNC_NAME(TypeName)) _GLIB_AUTOPTR_TYPENAME(TypeName)
+#define g_auto(TypeName) _GLIB_CLEANUP(_GLIB_AUTO_FUNC_NAME(TypeName)) TypeName
+
+#else /* not GNU C */
+
+#define G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func)
+#define G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func)
+#define G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func)
+
+/* no declaration of g_auto() or g_autoptr() here */
+#endif
+
 #endif /* __G_MACROS_H__ */


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