gobject: new g_set_weak_pointer() & g_clear_weak_pointer() helpers

Weak-pointers are currently lacking g_set_object() & g_clear_object()
helpers equivalent. New functions (and macros, both are provided) are
convenient in many case, especially for the property's notify-on-set
pattern:

  if (g_set_weak_pointer (...))
    g_object_notify (...)

Inspired by Christian Hergert's original implementation for
gnome-builder.

https://bugzilla.gnome.org/show_bug.cgi?id=749527
This commit is contained in:
Martin Blanchard
2017-12-20 23:05:53 +01:00
committed by Philip Withnall
parent 62c4768423
commit 156d32cb80
3 changed files with 210 additions and 0 deletions

View File

@@ -739,6 +739,108 @@ static inline gboolean
(g_set_object) ((GObject **) (object_ptr), (GObject *) (new_object)) \
)
/**
* g_clear_weak_pointer: (skip)
* @weak_pointer_location: The memory address of a pointer
*
* Clears a weak reference to a #GObject.
*
* @weak_pointer_location must not be %NULL.
*
* If the weak reference is %NULL then this function does nothing.
* Otherwise, the weak reference to the object is removed for that location
* and the pointer is set to %NULL.
*
* A macro is also included that allows this function to be used without
* pointer casts. The function itself is static inline, so its address may vary
* between compilation units.
*
* Since: 2.56
*/
static inline void
(g_clear_weak_pointer) (gpointer *weak_pointer_location)
{
GObject *object = (GObject *) *weak_pointer_location;
if (object != NULL)
{
g_object_remove_weak_pointer (object, weak_pointer_location);
*weak_pointer_location = NULL;
}
}
#define g_clear_weak_pointer(weak_pointer_location) \
(/* Check types match. */ \
(g_clear_weak_pointer) ((gpointer *) (weak_pointer_location)) \
)
/**
* g_set_weak_pointer: (skip)
* @weak_pointer_location: the memory address of a pointer
* @new_object: (nullable) (transfer none): a pointer to the new #GObject to
* assign to it, or %NULL to clear the pointer
*
* Updates a pointer to weakly refer to @new_object. It assigns @new_object
* to @weak_pointer_location and ensures that @weak_pointer_location will
* automaticaly be set to %NULL if @new_object gets destroyed. The assignment
* is not atomic. The weak reference is not thread-safe, see
* g_object_add_weak_pointer() for details.
*
* @weak_pointer_location must not be %NULL.
*
* A macro is also included that allows this function to be used without
* pointer casts. The function itself is static inline, so its address may vary
* between compilation units.
*
* One convenient usage of this function is in implementing property setters:
* |[
* void
* foo_set_bar (Foo *foo,
* Bar *new_bar)
* {
* g_return_if_fail (IS_FOO (foo));
* g_return_if_fail (new_bar == NULL || IS_BAR (new_bar));
*
* if (g_set_weak_pointer (&foo->bar, new_bar))
* g_object_notify (foo, "bar");
* }
* ]|
*
* Returns: %TRUE if the value of @weak_pointer_location changed, %FALSE otherwise
*
* Since: 2.56
*/
static inline gboolean
(g_set_weak_pointer) (gpointer *weak_pointer_location,
GObject *new_object)
{
GObject *old_object = (GObject *) *weak_pointer_location;
/* elide a (weak_pointer_location != NULL) check because most of the time we
* will be operating on struct members with a constant offset, so a NULL
* check would not catch bugs
*/
if (old_object == new_object)
return FALSE;
if (old_object != NULL)
g_object_remove_weak_pointer (old_object, weak_pointer_location);
*weak_pointer_location = new_object;
if (new_object != NULL)
g_object_add_weak_pointer (new_object, weak_pointer_location);
return TRUE;
}
#define g_set_weak_pointer(weak_pointer_location, new_object) \
(/* Check types match. */ \
0 ? *(weak_pointer_location) = (new_object), FALSE : \
(g_set_weak_pointer) ((gpointer *) (weak_pointer_location), (GObject *) (new_object)) \
)
typedef struct {
/*<private>*/
union { gpointer p; } priv;