mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 07:26:15 +01:00
utils: Add g_steal_handle_id() to complement g_clear_handle_id()
Just like we have `g_steal_pointer()` and `g_clear_pointer()`, it would be useful to have a ‘steal’ version of `g_clear_handle_id()`. Particularly in situations where a clear function can’t be represented as a `GClearHandleFunc`, such as `g_dbus_connection_signal_unsubscribe()` (there’s no way of passing the `GDBusConnection` to it) — or in situations where a handle ID isn’t being released, but is being passed from one struct to another or from a local scope to a struct or vice-versa. Includes unit tests. Signed-off-by: Philip Withnall <pwithnall@gnome.org>
This commit is contained in:
parent
cc2b78ec47
commit
431e75fa36
45
glib/gmain.h
45
glib/gmain.h
@ -866,6 +866,51 @@ void g_clear_handle_id (guint *tag_ptr,
|
||||
} G_STMT_END \
|
||||
GLIB_AVAILABLE_MACRO_IN_2_56
|
||||
|
||||
/**
|
||||
* g_steal_handle_id:
|
||||
* @handle_pointer: (inout) (not optional): a pointer to a handle ID
|
||||
*
|
||||
* Sets @handle_pointer to `0`, returning the value that was there before.
|
||||
*
|
||||
* Conceptually, this transfers the ownership of the handle ID from the
|
||||
* referenced variable to the ‘caller’ of the macro (ie: ‘steals’ the
|
||||
* handle ID).
|
||||
*
|
||||
* This can be very useful to make ownership transfer explicit, or to prevent
|
||||
* a handle from being released multiple times. For example:
|
||||
*
|
||||
* ```c
|
||||
* void
|
||||
* maybe_unsubscribe_signal (ContextStruct *data)
|
||||
* {
|
||||
* if (some_complex_logic (data))
|
||||
* {
|
||||
* g_dbus_connection_signal_unsubscribe (data->connection,
|
||||
* g_steal_handle_id (&data->subscription_id));
|
||||
* // now data->subscription_id isn’t a dangling handle
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* While [func@GLib.clear_handle_id] can be used in many of the same situations
|
||||
* as `g_steal_handle_id()`, this is one situation where it cannot be used, as
|
||||
* there is no way to pass the `GDBusConnection` to a
|
||||
* [type@GLib.ClearHandleFunc].
|
||||
*
|
||||
* Since: 2.84
|
||||
*/
|
||||
GLIB_AVAILABLE_STATIC_INLINE_IN_2_84
|
||||
static inline unsigned int
|
||||
g_steal_handle_id (unsigned int *handle_pointer)
|
||||
{
|
||||
unsigned int handle;
|
||||
|
||||
handle = *handle_pointer;
|
||||
*handle_pointer = 0;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/* Idles, child watchers and timeouts */
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
guint g_timeout_add_full (gint priority,
|
||||
|
@ -1322,6 +1322,20 @@ test_clear_slist (void)
|
||||
g_assert_null (slist);
|
||||
}
|
||||
|
||||
static void
|
||||
test_steal_handle_id (void)
|
||||
{
|
||||
unsigned int handle_id = 0;
|
||||
|
||||
g_assert_cmpuint (g_steal_handle_id (&handle_id), ==, 0);
|
||||
g_assert_cmpuint (handle_id, ==, 0);
|
||||
|
||||
handle_id = 5; /* pretend this is a meaningful handle */
|
||||
|
||||
g_assert_cmpuint (g_steal_handle_id (&handle_id), ==, 5);
|
||||
g_assert_cmpuint (handle_id, ==, 0);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -1382,6 +1396,7 @@ main (int argc,
|
||||
g_test_add_func ("/utils/int-limits", test_int_limits);
|
||||
g_test_add_func ("/utils/clear-list", test_clear_list);
|
||||
g_test_add_func ("/utils/clear-slist", test_clear_slist);
|
||||
g_test_add_func ("/utils/steal-handle-id", test_steal_handle_id);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user