Add g_autofree
authorColin Walters <walters@verbum.org>
Sun, 15 Feb 2015 13:58:44 +0000 (08:58 -0500)
committerColin Walters <walters@verbum.org>
Mon, 23 Feb 2015 03:18:07 +0000 (22:18 -0500)
The g_autoptr() being associated with the type name works out really
well for things like GHashTable.  However, it's a bit more awkward to
associate with "gchar".  Also because one can't use "char".
Similarly, there are a lot of other "bare primitive array" types that
one might reasonably use.

This patch does not remove the autoptr for "gchar", even though I
think it's rather awkward and strange.

Also while we're here, add a test case for the cleanup bits.

https://bugzilla.gnome.org/show_bug.cgi?id=744747

glib/docs.c
glib/glib-autocleanups.h
glib/gmacros.h
glib/tests/Makefile.am
glib/tests/autoptr.c [new file with mode: 0644]

index f7a0bf2..9169d85 100644 (file)
  */
 
 /**
+ * g_autofree:
+ *
+ * Macro to add an attribute to pointer variable to ensure automatic
+ * cleanup using g_free().
+ *
+ * This macro differs from g_autoptr() in that it is an attribute supplied
+ * before the type name, rather than wrapping the type definition.  Instead
+ * of using a type-specific lookup, this macro always calls g_free() directly.
+ *
+ * This means it's useful for any type that is returned from
+ * g_malloc().
+ *
+ * Otherwise, this macro has similar constraints as g_autoptr() - only
+ * supported on GCC and clang, the variable must be initialized, etc.
+ *
+ * |[
+ * gboolean
+ * operate_on_malloc_buf (void)
+ * {
+ *   g_autofree guint8* membuf = NULL;
+ *
+ *   membuf = g_malloc (8192);
+ *
+ *   /* Some computation on membuf */
+ *
+ *   /* membuf will be automatically freed here */
+ *   return TRUE;
+ * }
+ * ]|
+ *
+ * Since: 2.44
+ */
+
+/**
  * G_DEFINE_AUTOPTR_CLEANUP_FUNC:
  * @TypeName: a type name to define a g_autoptr() cleanup function for
  * @func: the cleanup function
index 902e952..80d7b2b 100644 (file)
 #error "Only <glib.h> can be included directly."
 #endif
 
+static inline void
+g_autoptr_cleanup_generic_gfree (void *p)
+{ 
+  void **pp = (void**)p;
+  if (*pp)
+    g_free (*pp);
+}
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAsyncQueue, g_async_queue_unref)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBookmarkFile, g_bookmark_file_free)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBytes, g_bytes_unref)
index 62b61cb..b34cc77 100644 (file)
   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
+#define g_autofree _GLIB_CLEANUP(g_autoptr_cleanup_generic_gfree)
 
 #else /* not GNU C */
 /* this (dummy) macro is private */
index 445040a..bdcd0cb 100644 (file)
@@ -200,6 +200,12 @@ check-am: gtester-xmllint-check
 private_LDFLAGS = @G_THREAD_LIBS@
 endif
 
+if HAVE_GCC
+test_programs += \
+       autoptr                         \
+       $(NULL)
+endif
+
 # -----------------------------------------------------------------------------
 
 if HAVE_EVENTFD
diff --git a/glib/tests/autoptr.c b/glib/tests/autoptr.c
new file mode 100644 (file)
index 0000000..b2db335
--- /dev/null
@@ -0,0 +1,37 @@
+#include <glib.h>
+
+static void
+test_autofree (void)
+{
+  g_autofree char *p = NULL;
+  g_autofree char *p2 = NULL;
+  g_autofree char *alwaysnull = NULL;
+
+  p = g_malloc (10);
+  p2 = g_malloc (42);
+
+  if (TRUE)
+    {
+      g_autofree guint8 *buf = g_malloc (128);
+      g_autofree char *alwaysnull_again = NULL;
+
+      buf[0] = 1;
+    }
+
+  if (TRUE)
+    {
+      g_autofree guint8 *buf2 = g_malloc (256);
+
+      buf2[255] = 42;
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/autoptr/autofree", test_autofree);
+
+  return g_test_run ();
+}