[glib/finalize-speedups: 1/5] Add g_datalist_id_remove_multiple




commit 911ec0fd82628a5512824f23d0dca65749a4a5bc
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.

 docs/reference/glib/glib-sections.txt |   1 +
 glib/gdataset.c                       | 101 ++++++++++++++++++++++++++++++++++
 glib/gdataset.h                       |   4 ++
 3 files changed, 106 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..298c723b78 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,27 @@ 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
+ *
+ * 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,
+                               guint    n_keys)
+{
+  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..f9731c6cb5 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,
+                                         guint              n_keys);
 
 typedef gpointer (*GDuplicateFunc) (gpointer data, gpointer user_data);
 


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