gstring: Add a new g_string_copy() method

This does a deep copy on the `GString`.

It means we can eliminate the less-efficient version currently used for
`GBoxed`, which also has `-Wsign-conversion` problems. See the following
commit.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3405
This commit is contained in:
Philip Withnall 2025-04-11 14:55:59 +01:00
parent b6937c9b32
commit 3048266aa3
No known key found for this signature in database
GPG Key ID: C5C42CFB268637CA
3 changed files with 69 additions and 0 deletions

View File

@ -214,6 +214,38 @@ g_string_new_len (const gchar *init,
}
}
/**
* g_string_copy:
* @string: a string
*
* Copies the [struct@GLib.String] instance and its contents.
*
* This will preserve the allocation length of the [struct@GLib.String] in the
* copy.
*
* Returns: (transfer full): a copy of @string
* Since: 2.86
*/
GString *
g_string_copy (GString *string)
{
GString *copy = NULL;
g_return_val_if_fail (string != NULL, NULL);
copy = g_slice_new (GString);
copy->allocated_len = string->allocated_len;
copy->len = string->len;
/* We cant just strdup(string->str) here because it may contain embedded nuls. */
copy->str = g_malloc (string->allocated_len);
if (string->str != NULL && string->len > 0)
memcpy (copy->str, string->str, string->len);
copy->str[copy->len] = '\0';
return g_steal_pointer (&copy);
}
/**
* g_string_free:
* @string: (transfer full): a #GString

View File

@ -58,6 +58,8 @@ GString* g_string_new_len (const gchar *init,
gssize len);
GLIB_AVAILABLE_IN_ALL
GString* g_string_sized_new (gsize dfl_size);
GLIB_AVAILABLE_IN_2_86
GString *g_string_copy (GString *string);
GLIB_AVAILABLE_IN_ALL
gchar* (g_string_free) (GString *string,
gboolean free_segment);

View File

@ -767,6 +767,40 @@ test_string_new_take_null (void)
g_string_free (g_steal_pointer (&string), TRUE);
}
static void
test_string_copy (void)
{
GString *string1 = NULL, *string2 = NULL;
string1 = g_string_new ("hello");
string2 = g_string_copy (string1);
g_assert_cmpstr (string1->str, ==, string2->str);
g_assert_true (string1->str != string2->str);
g_assert_cmpuint (string1->len, ==, string2->len);
g_assert_cmpuint (string2->allocated_len, ==, string2->allocated_len);
g_string_free (string1, TRUE);
g_string_free (string2, TRUE);
string1 = g_string_sized_new (100);
string2 = g_string_copy (string1);
g_assert_cmpstr (string1->str, ==, string2->str);
g_assert_true (string1->str != string2->str);
g_assert_cmpuint (string1->len, ==, string2->len);
g_assert_cmpuint (string2->allocated_len, ==, string2->allocated_len);
g_string_free (string1, TRUE);
g_string_free (string2, TRUE);
string1 = g_string_sized_new (200);
g_string_append_len (string1, "test with embedded\0nuls", 25);
string2 = g_string_copy (string1);
g_assert_cmpmem (string1->str, string1->len, string2->str, string2->len);
g_assert_true (string1->str != string2->str);
g_assert_cmpuint (string1->len, ==, string2->len);
g_assert_cmpuint (string2->allocated_len, ==, string2->allocated_len);
g_string_free (string1, TRUE);
g_string_free (string2, TRUE);
}
int
main (int argc,
char *argv[])
@ -796,6 +830,7 @@ main (int argc,
g_test_add_func ("/string/steal", test_string_steal);
g_test_add_func ("/string/new-take", test_string_new_take);
g_test_add_func ("/string/new-take/null", test_string_new_take_null);
g_test_add_func ("/string/copy", test_string_copy);
return g_test_run();
}