mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
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:
parent
62c4768423
commit
156d32cb80
@ -279,6 +279,8 @@ g_object_weak_ref
|
|||||||
g_object_weak_unref
|
g_object_weak_unref
|
||||||
g_object_add_weak_pointer
|
g_object_add_weak_pointer
|
||||||
g_object_remove_weak_pointer
|
g_object_remove_weak_pointer
|
||||||
|
g_set_weak_pointer
|
||||||
|
g_clear_weak_pointer
|
||||||
GToggleNotify
|
GToggleNotify
|
||||||
g_object_add_toggle_ref
|
g_object_add_toggle_ref
|
||||||
g_object_remove_toggle_ref
|
g_object_remove_toggle_ref
|
||||||
|
@ -739,6 +739,108 @@ static inline gboolean
|
|||||||
(g_set_object) ((GObject **) (object_ptr), (GObject *) (new_object)) \
|
(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 {
|
typedef struct {
|
||||||
/*<private>*/
|
/*<private>*/
|
||||||
union { gpointer p; } priv;
|
union { gpointer p; } priv;
|
||||||
|
@ -313,6 +313,108 @@ test_weak_pointer (void)
|
|||||||
g_assert (weak2 == obj);
|
g_assert (weak2 == obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_weak_pointer_clear (void)
|
||||||
|
{
|
||||||
|
GObject *obj;
|
||||||
|
gpointer weak = NULL;
|
||||||
|
|
||||||
|
g_clear_weak_pointer (&weak);
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
|
||||||
|
g_object_add_weak_pointer (obj, &weak);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_true (weak == obj);
|
||||||
|
|
||||||
|
g_clear_weak_pointer (&weak);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
g_object_unref (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_weak_pointer_clear_function (void)
|
||||||
|
{
|
||||||
|
GObject *obj;
|
||||||
|
gpointer weak = NULL;
|
||||||
|
|
||||||
|
(g_clear_weak_pointer) (&weak);
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
weak = obj = g_object_new (G_TYPE_OBJECT, NULL);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
|
||||||
|
g_object_add_weak_pointer (obj, &weak);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_true (weak == obj);
|
||||||
|
|
||||||
|
(g_clear_weak_pointer) (&weak);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
g_object_unref (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_weak_pointer_set (void)
|
||||||
|
{
|
||||||
|
GObject *obj;
|
||||||
|
gpointer weak = NULL;
|
||||||
|
|
||||||
|
g_assert_false (g_set_weak_pointer (&weak, NULL));
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
obj = g_object_new (G_TYPE_OBJECT, NULL);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
|
||||||
|
g_assert_true (g_set_weak_pointer (&weak, obj));
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_true (weak == obj);
|
||||||
|
|
||||||
|
g_assert_true (g_set_weak_pointer (&weak, NULL));
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
g_assert_true (g_set_weak_pointer (&weak, obj));
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_true (weak == obj);
|
||||||
|
|
||||||
|
g_object_unref (obj);
|
||||||
|
g_assert_null (weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_weak_pointer_set_function (void)
|
||||||
|
{
|
||||||
|
GObject *obj;
|
||||||
|
gpointer weak = NULL;
|
||||||
|
|
||||||
|
g_assert_false ((g_set_weak_pointer) (&weak, NULL));
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
obj = g_object_new (G_TYPE_OBJECT, NULL);
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
|
||||||
|
g_assert_true ((g_set_weak_pointer) (&weak, obj));
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_true (weak == obj);
|
||||||
|
|
||||||
|
g_assert_true ((g_set_weak_pointer) (&weak, NULL));
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_null (weak);
|
||||||
|
|
||||||
|
g_assert_true ((g_set_weak_pointer) (&weak, obj));
|
||||||
|
g_assert_cmpint (obj->ref_count, ==, 1);
|
||||||
|
g_assert_true (weak == obj);
|
||||||
|
|
||||||
|
g_object_unref (obj);
|
||||||
|
g_assert_null (weak);
|
||||||
|
}
|
||||||
|
|
||||||
/* See gobject/tests/threadtests.c for the threaded version */
|
/* See gobject/tests/threadtests.c for the threaded version */
|
||||||
static void
|
static void
|
||||||
test_weak_ref (void)
|
test_weak_ref (void)
|
||||||
@ -667,6 +769,10 @@ main (int argc, char **argv)
|
|||||||
g_test_add_func ("/object/value", test_object_value);
|
g_test_add_func ("/object/value", test_object_value);
|
||||||
g_test_add_func ("/object/initially-unowned", test_initially_unowned);
|
g_test_add_func ("/object/initially-unowned", test_initially_unowned);
|
||||||
g_test_add_func ("/object/weak-pointer", test_weak_pointer);
|
g_test_add_func ("/object/weak-pointer", test_weak_pointer);
|
||||||
|
g_test_add_func ("/object/weak-pointer/clear", test_weak_pointer_clear);
|
||||||
|
g_test_add_func ("/object/weak-pointer/clear-function", test_weak_pointer_clear_function);
|
||||||
|
g_test_add_func ("/object/weak-pointer/set", test_weak_pointer_set);
|
||||||
|
g_test_add_func ("/object/weak-pointer/set-function", test_weak_pointer_set_function);
|
||||||
g_test_add_func ("/object/weak-ref", test_weak_ref);
|
g_test_add_func ("/object/weak-ref", test_weak_ref);
|
||||||
g_test_add_func ("/object/toggle-ref", test_toggle_ref);
|
g_test_add_func ("/object/toggle-ref", test_toggle_ref);
|
||||||
g_test_add_func ("/object/qdata", test_object_qdata);
|
g_test_add_func ("/object/qdata", test_object_qdata);
|
||||||
|
Loading…
Reference in New Issue
Block a user