From 7880d870919d58b751f6bc47669052b45eb9db30 Mon Sep 17 00:00:00 2001 From: Alexander Slobodeniuk Date: Fri, 3 Nov 2023 17:00:11 +0100 Subject: [PATCH] gvalue: add g_value_steal_string() This call is needed to avoid an extra copy after serialization of the data. --- docs/reference/gobject/gobject-sections.txt | 1 + gobject/gvaluetypes.c | 35 +++++++++++++++++++++ gobject/gvaluetypes.h | 2 ++ gobject/tests/value.c | 23 +++++++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index cf06cf183..3f7f67386 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -719,6 +719,7 @@ g_value_take_string g_value_set_string_take_ownership g_value_get_string g_value_dup_string +g_value_steal_string g_value_set_interned_string diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c index 6ffa7fd8b..6ed6d9cce 100644 --- a/gobject/gvaluetypes.c +++ b/gobject/gvaluetypes.c @@ -1159,6 +1159,41 @@ g_value_dup_string (const GValue *value) return g_strdup (value->data[0].v_pointer); } +/** + * g_value_steal_string: + * @value: a valid #GValue of type %G_TYPE_STRING + * + * Steal ownership on contents of a %G_TYPE_STRING #GValue. + * As a result of this operation the value's contents will be reset to %NULL. + * + * The purpose of this call is to provide a way to avoid an extra copy + * when some object have been serialized into string through #GValue API. + * + * NOTE: for safety and compatibility purposes, if #GValue contains + * static string, or an interned one, this function will return a copy + * of the string. Otherwise the transfer notation would be ambiguous. + * + * Returns: (nullable) (transfer full): string content of @value; + * Should be freed with g_free() when no longer needed. + * + * Since: 2.80 + */ +gchar* +g_value_steal_string (GValue *value) +{ + gchar *ret; + + g_return_val_if_fail (G_VALUE_HOLDS_STRING (value), NULL); + + ret = value->data[0].v_pointer; + value->data[0].v_pointer = NULL; + + if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) + return g_strdup (ret); + + return ret; +} + /** * g_value_set_pointer: * @value: a valid #GValue of %G_TYPE_POINTER diff --git a/gobject/gvaluetypes.h b/gobject/gvaluetypes.h index 0c8d0f66e..afa659530 100644 --- a/gobject/gvaluetypes.h +++ b/gobject/gvaluetypes.h @@ -263,6 +263,8 @@ GOBJECT_AVAILABLE_IN_ALL const gchar * g_value_get_string (const GValue *value); GOBJECT_AVAILABLE_IN_ALL gchar* g_value_dup_string (const GValue *value); +GOBJECT_AVAILABLE_IN_2_80 +gchar* g_value_steal_string (GValue *value); GOBJECT_AVAILABLE_IN_ALL void g_value_set_pointer (GValue *value, gpointer v_pointer); diff --git a/gobject/tests/value.c b/gobject/tests/value.c index 73a5de650..d1a90919a 100644 --- a/gobject/tests/value.c +++ b/gobject/tests/value.c @@ -420,7 +420,7 @@ test_value_string (void) const gchar *static2 = "static2"; const gchar *storedstr; const gchar *copystr; - gchar *str1, *str2; + gchar *str1, *str2, *stolen_str; GValue value = G_VALUE_INIT; GValue copy = G_VALUE_INIT; @@ -513,7 +513,12 @@ test_value_string (void) g_assert_true (storedstr != static2); g_assert_cmpstr (storedstr, ==, static2); + /* Now check stealing the ownership of the contents */ + stolen_str = g_value_steal_string (&value); + g_assert_null (g_value_get_string (&value)); g_value_unset (&value); + g_assert_cmpstr (stolen_str, ==, static2); + g_free (stolen_str); /* * Static strings @@ -544,6 +549,14 @@ test_value_string (void) g_assert_true (storedstr != static1); g_assert_cmpstr (storedstr, ==, static2); + /* Check if g_value_steal_string() can handle GValue + * with a static string */ + stolen_str = g_value_steal_string (&value); + g_assert_true (stolen_str != static2); + g_assert_cmpstr (stolen_str, ==, static2); + g_assert_null (g_value_get_string (&value)); + g_free (stolen_str); + g_value_unset (&value); /* @@ -588,6 +601,14 @@ test_value_string (void) g_assert_true (storedstr != static2); g_assert_cmpstr (storedstr, ==, static2); + /* Check if g_value_steal_string() can handle GValue + * with an interned string */ + stolen_str = g_value_steal_string (&value); + g_assert_true (stolen_str != static2); + g_assert_cmpstr (stolen_str, ==, static2); + g_assert_null (g_value_get_string (&value)); + g_free (stolen_str); + g_value_unset (&value); }