[glib/refcount-box] Make g_rc_box_dup()/g_arc_box_dup() more generic



commit b3bbec026ac55a8b9b1968f333b1719b86af6260
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Jun 11 17:14:12 2018 +0100

    Make g_rc_box_dup()/g_arc_box_dup() more generic
    
    It's more useful to have a dup() function that copies any blob of memory
    into a reference counted allocation, than to have a dup() that only
    copies a reference counted allocation.

 glib/garcbox.c     | 21 +++++++-------
 glib/grcbox.c      | 19 ++++++-------
 glib/grcbox.h      | 14 ++++++----
 glib/tests/rcbox.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 103 insertions(+), 33 deletions(-)
---
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 9be7a460a..da7b388e3 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 <http://www.gnu.org/licenses/>.
+ */
+
 #include <glib.h>
 
 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)
 {
@@ -20,14 +39,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)
 {
@@ -49,16 +72,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
@@ -68,8 +138,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 ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]