diff --git a/glib/garcbox.c b/glib/garcbox.c index ea6e742d8..aaa2c8b56 100644 --- a/glib/garcbox.c +++ b/glib/garcbox.c @@ -222,29 +222,28 @@ g_arc_box_alloc0 (gsize block_size) /** * g_arc_box_dup: - * @mem_block: (not nullable): a pointer to reference counted data + * @block_size: the number of bytes to copy + * @mem_block: (not nullable): the memory to copy * - * Allocates a new block of data with atomic reference counting - * semantics, and copies the contents of @mem_block into - * it. + * Allocates a new block of data with atomit reference counting + * semantics, and copies @block_size bytes of @mem_block + * into it. * * Returns: (not nullable): a pointer to the allocated memory * * Since: 2.58 */ gpointer -(g_arc_box_dup) (gpointer mem_block) +(g_arc_box_dup) (gsize block_size, + gconstpointer mem_block) { - GArcBox *real_box = G_ARC_BOX (mem_block); gpointer res; + g_return_val_if_fail (block_size > 0, NULL); g_return_val_if_fail (mem_block != NULL, NULL); -#ifndef G_DISABLE_ASSERT - g_return_val_if_fail (real_box->magic == G_BOX_MAGIC, NULL); -#endif - res = g_rc_box_alloc_full (real_box->mem_size, TRUE, FALSE); - memcpy (res, mem_block, real_box->mem_size); + res = g_rc_box_alloc_full (block_size, TRUE, FALSE); + memcpy (res, mem_block, block_size); return res; } diff --git a/glib/grcbox.c b/glib/grcbox.c index d41a6def4..d65f4c919 100644 --- a/glib/grcbox.c +++ b/glib/grcbox.c @@ -286,29 +286,28 @@ g_rc_box_alloc0 (gsize block_size) /** * g_rc_box_dup: - * @mem_block: (not nullable): a pointer to reference counted data + * @block_size: the number of bytes to copy + * @mem_block: (not nullable): the memory to copy * * Allocates a new block of data with reference counting - * semantics, and copies the contents of @mem_block into - * it. + * semantics, and copies @block_size bytes of @mem_block + * into it. * * Returns: (not nullable): a pointer to the allocated memory * * Since: 2.58 */ gpointer -(g_rc_box_dup) (gpointer mem_block) +(g_rc_box_dup) (gsize block_size, + gconstpointer mem_block) { - GRcBox *real_box = G_RC_BOX (mem_block); gpointer res; + g_return_val_if_fail (block_size > 0, NULL); g_return_val_if_fail (mem_block != NULL, NULL); -#ifndef G_DISABLE_ASSERT - g_return_val_if_fail (real_box->magic == G_BOX_MAGIC, NULL); -#endif - res = g_rc_box_alloc_full (real_box->mem_size, FALSE, FALSE); - memcpy (res, mem_block, real_box->mem_size); + res = g_rc_box_alloc_full (block_size, FALSE, FALSE); + memcpy (res, mem_block, block_size); return res; } diff --git a/glib/grcbox.h b/glib/grcbox.h index 2b38815d8..3f364d330 100644 --- a/glib/grcbox.h +++ b/glib/grcbox.h @@ -31,7 +31,8 @@ gpointer g_rc_box_alloc (gsize block_size) G_GNUC_MALL GLIB_AVAILABLE_IN_2_58 gpointer g_rc_box_alloc0 (gsize block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); GLIB_AVAILABLE_IN_2_58 -gpointer g_rc_box_dup (gpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_rc_box_dup (gsize block_size, + gconstpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); GLIB_AVAILABLE_IN_2_58 gpointer g_rc_box_acquire (gpointer mem_block); GLIB_AVAILABLE_IN_2_58 @@ -45,7 +46,8 @@ gpointer g_arc_box_alloc (gsize block_size) G_GNUC_MALL GLIB_AVAILABLE_IN_2_58 gpointer g_arc_box_alloc0 (gsize block_size) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); GLIB_AVAILABLE_IN_2_58 -gpointer g_arc_box_dup (gpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); +gpointer g_arc_box_dup (gsize block_size, + gconstpointer mem_block) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); GLIB_AVAILABLE_IN_2_58 gpointer g_arc_box_acquire (gpointer mem_block); GLIB_AVAILABLE_IN_2_58 @@ -71,10 +73,10 @@ void g_arc_box_release_full (gpointer mem_block, ((__typeof__(mem_block)) (g_arc_box_acquire) (mem_block)) /* Type check to avoid duplicating data to different types */ -# define g_rc_box_dup(mem_block) \ - ((__typeof__(mem_block)) (g_rc_box_dup) (mem_block)) -# define g_arc_box_dup(mem_block) \ - ((__typeof__(mem_block)) (g_arc_box_dup) (mem_block)) +# define g_rc_box_dup(block_size,mem_block) \ + ((__typeof__(mem_block)) (g_rc_box_dup) (block_size,mem_block)) +# define g_arc_box_dup(block_size,mem_block) \ + ((__typeof__(mem_block)) (g_arc_box_dup) (block_size,mem_block)) #endif G_END_DECLS diff --git a/glib/tests/rcbox.c b/glib/tests/rcbox.c index 19b3842e5..4a33876bc 100644 --- a/glib/tests/rcbox.c +++ b/glib/tests/rcbox.c @@ -1,3 +1,21 @@ +/* rcbox.c: Reference counted data + * + * Copyright 2018 Emmanuele Bassi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + #include typedef struct { @@ -6,6 +24,7 @@ typedef struct { static Point *global_point; +/* test_rcbox_new: Test g_rc_box_new() */ static void test_rcbox_new (void) { @@ -27,14 +46,18 @@ static void point_clear (Point *p) { g_assert_nonnull (p); + g_assert_true (global_point == p); g_assert_cmpfloat (p->x, ==, 42.0f); g_assert_cmpfloat (p->y, ==, 47.0f); - g_assert_true (global_point == p); + g_test_message ("global_point = %p", p); global_point = NULL; } +/* test_rcbox_release_full: Verify that g_rc_box_release_full() calls + * the clear function only when the last reference is released + */ static void test_rcbox_release_full (void) { @@ -56,16 +79,63 @@ test_rcbox_release_full (void) g_assert_null (global_point); } +static Point *global_point_a; +static Point *global_point_b; + +static void +point_clear_dup_a (Point *a) +{ + g_assert_true (a == global_point_a); + + g_test_message ("global_point_a = %p", a); + global_point_a = NULL; +} + +static void +point_clear_dup_b (Point *b) +{ + g_assert_true (b == global_point_b); + + g_test_message ("global_point_b = %p", b); + global_point_b = NULL; +} + +/* test_rcbox_dup: Verify that g_rc_box_dup() copies only the + * data and does not change the reference count of the original + */ static void test_rcbox_dup (void) { - Point *a = g_rc_box_new (Point); - Point *b = g_rc_box_dup (a); + Point *a, *b; + a = g_rc_box_new (Point); + a->x = 10.f; + a->y = 5.f; + + b = g_rc_box_dup (sizeof (Point), a); g_assert_true (a != b); + g_assert_cmpfloat (a->x, ==, b->x); + g_assert_cmpfloat (a->y, ==, b->y); - g_rc_box_release (a); - g_rc_box_release (b); + global_point_a = a; + global_point_b = b; + + a->x = 1.f; + a->y = 1.f; + g_assert_cmpfloat (a->x, !=, b->x); + g_assert_cmpfloat (a->y, !=, b->y); + + b->x = 5.f; + b->y = 10.f; + g_assert_cmpfloat (a->x, !=, b->x); + g_assert_cmpfloat (a->y, !=, b->y); + + g_rc_box_release_full (a, (GDestroyNotify) point_clear_dup_a); + g_assert_null (global_point_a); + g_assert_nonnull (global_point_b); + + g_rc_box_release_full (b, (GDestroyNotify) point_clear_dup_b); + g_assert_null (global_point_b); } int @@ -75,8 +145,8 @@ main (int argc, g_test_init (&argc, &argv, NULL); g_test_add_func ("/rcbox/new", test_rcbox_new); - g_test_add_func ("/rcbox/dup", test_rcbox_dup); g_test_add_func ("/rcbox/release-full", test_rcbox_release_full); + g_test_add_func ("/rcbox/dup", test_rcbox_dup); return g_test_run (); }