[glib/finalize-speedups: 8/11] Add g_datalist_id_remove_multiple




commit a7765534efdb4f3dcfb0ba39193d8c83f1d73b22
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun May 22 06:47:55 2022 -0400

    Add g_datalist_id_remove_multiple
    
    This is more efficient than calling
    g_datalist_id_remove() multiple times
    in a row, since it only takes the locks
    once.
    
    Allow up to 16 keys to be removed in one go.
    That is enough for the use we have in GObject,
    and it avoids any danger of blowing the stack.

 docs/reference/glib/glib-sections.txt |   1 +
 glib/gdataset.c                       | 103 ++++++++++++++++++++++++++++++++++
 glib/gdataset.h                       |   4 ++
 3 files changed, 108 insertions(+)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 2932313cd0..bacf386840 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -3220,6 +3220,7 @@ g_datalist_id_set_data_full
 g_datalist_id_get_data
 g_datalist_id_remove_data
 g_datalist_id_remove_no_notify
+g_datalist_id_remove_multiple
 GDuplicateFunc
 g_datalist_id_dup_data
 g_datalist_id_replace_data
diff --git a/glib/gdataset.c b/glib/gdataset.c
index 758c032ab3..87699d8457 100644
--- a/glib/gdataset.c
+++ b/glib/gdataset.c
@@ -46,6 +46,7 @@
 #include "gtestutils.h"
 #include "gthread.h"
 #include "glib_trace.h"
+#include "galloca.h"
 
 /**
  * SECTION:datasets
@@ -487,6 +488,85 @@ g_data_set_internal (GData   **datalist,
 
 }
 
+static inline void
+g_data_remove_internal (GData  **datalist,
+                        GQuark  *keys,
+                        gsize    n_keys)
+{
+  GData *d;
+
+  g_datalist_lock (datalist);
+
+  d = G_DATALIST_GET_POINTER (datalist);
+
+  if (d)
+    {
+      GDataElt *old, *data, *data_end;
+      gsize found_keys;
+
+      old = g_newa (GDataElt, n_keys);
+
+      data = d->data;
+      data_end = data + d->len;
+      found_keys = 0;
+
+      while (data < data_end && found_keys < n_keys)
+        {
+          gboolean remove = FALSE;
+
+          for (gsize i = 0; i < n_keys; i++)
+            {
+              if (data->key == keys[i])
+                {
+                  remove = TRUE;
+                  break;
+                }
+            }
+
+          if (remove)
+            {
+              old[found_keys] = *data;
+              found_keys++;
+
+              if (data < data_end)
+                {
+                  data_end--;
+                  *data = *data_end;
+                }
+
+              d->len--;
+
+              /* We don't bother to shrink, but if all data are now gone
+               * we at least free the memory
+               */
+              if (d->len == 0)
+                {
+                  G_DATALIST_SET_POINTER (datalist, NULL);
+                  g_free (d);
+                  break;
+                }
+            }
+
+          data++;
+        }
+
+      if (found_keys > 0)
+        {
+          g_datalist_unlock (datalist);
+
+          for (gsize i = 0; i < found_keys; i++)
+            {
+              if (old[i].destroy)
+                old[i].destroy (old[i].data);
+            }
+
+          return;
+        }
+    }
+
+  g_datalist_unlock (datalist);
+}
+
 /**
  * g_dataset_id_set_data_full: (skip)
  * @dataset_location: (not nullable): the location identifying the dataset.
@@ -672,6 +752,29 @@ g_datalist_id_set_data_full (GData   **datalist,
   g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
 }
 
+/**
+ * g_datalist_id_remove_multiple:
+ * @datalist: a datalist
+ * @keys: (array length=n_keys): keys to remove
+ * @n_keys: length of @keys, must be <= 16
+ *
+ * Removes multiple keys from a datalist.
+ *
+ * This is more efficient than calling g_datalist_id_remove()
+ * multiple times in a row.
+ *
+ * Since: 2.74
+ */
+void
+g_datalist_id_remove_multiple (GData  **datalist,
+                               GQuark  *keys,
+                               gsize    n_keys)
+{
+  g_return_if_fail (n_keys <= 16);
+
+  g_data_remove_internal (datalist, keys, n_keys);
+}
+
 /**
  * g_dataset_id_remove_no_notify: (skip)
  * @dataset_location: (not nullable): the location identifying the dataset.
diff --git a/glib/gdataset.h b/glib/gdataset.h
index a85179c60d..a0d44b09ec 100644
--- a/glib/gdataset.h
+++ b/glib/gdataset.h
@@ -55,6 +55,10 @@ void     g_datalist_id_set_data_full    (GData            **datalist,
                                         GQuark             key_id,
                                         gpointer           data,
                                         GDestroyNotify     destroy_func);
+GLIB_AVAILABLE_IN_2_74
+void     g_datalist_id_remove_multiple  (GData            **datalist,
+                                         GQuark            *keys,
+                                         gsize              n_keys);
 
 typedef gpointer (*GDuplicateFunc) (gpointer data, gpointer user_data);
 


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