LCOV - code coverage report
Current view: top level - glib - gdataset.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 96.4 % 449 433
Test Date: 2026-01-20 05:15:58 Functions: 100.0 % 33 33
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GLIB - Library of useful routines for C programming
       2                 :             :  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       3                 :             :  *
       4                 :             :  * gdataset.c: Generic dataset mechanism, similar to GtkObject data.
       5                 :             :  * Copyright (C) 1998 Tim Janik
       6                 :             :  *
       7                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       8                 :             :  *
       9                 :             :  * This library is free software; you can redistribute it and/or
      10                 :             :  * modify it under the terms of the GNU Lesser General Public
      11                 :             :  * License as published by the Free Software Foundation; either
      12                 :             :  * version 2.1 of the License, or (at your option) any later version.
      13                 :             :  *
      14                 :             :  * This library is distributed in the hope that it will be useful,
      15                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17                 :             :  * Lesser General Public License for more details.
      18                 :             :  *
      19                 :             :  * You should have received a copy of the GNU Lesser General Public
      20                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      21                 :             :  */
      22                 :             : 
      23                 :             : /*
      24                 :             :  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      25                 :             :  * file for a list of people on the GLib Team.  See the ChangeLog
      26                 :             :  * files for a list of changes.  These files are distributed with
      27                 :             :  * GLib at ftp://ftp.gtk.org/pub/gtk/.
      28                 :             :  */
      29                 :             : 
      30                 :             : /*
      31                 :             :  * MT safe ; except for g_data*_foreach()
      32                 :             :  */
      33                 :             : 
      34                 :             : #include "config.h"
      35                 :             : 
      36                 :             : #include <string.h>
      37                 :             : 
      38                 :             : #include "gdataset.h"
      39                 :             : #include "gbitlock.h"
      40                 :             : 
      41                 :             : #include "gslice.h"
      42                 :             : #include "gdatasetprivate.h"
      43                 :             : #include "gutilsprivate.h"
      44                 :             : #include "ghash.h"
      45                 :             : #include "gquark.h"
      46                 :             : #include "gstrfuncs.h"
      47                 :             : #include "gtestutils.h"
      48                 :             : #include "gthread.h"
      49                 :             : #include "glib_trace.h"
      50                 :             : #include "galloca.h"
      51                 :             : 
      52                 :             : /**
      53                 :             :  * GData:
      54                 :             :  *
      55                 :             :  * An opaque data structure that represents a keyed data list.
      56                 :             :  *
      57                 :             :  * See also: [Keyed data lists](datalist-and-dataset.html).
      58                 :             :  **/
      59                 :             : 
      60                 :             : /**
      61                 :             :  * GDestroyNotify:
      62                 :             :  * @data: the data element.
      63                 :             :  *
      64                 :             :  * Specifies the type of function which is called when a data element
      65                 :             :  * is destroyed. It is passed the pointer to the data element and
      66                 :             :  * should free any memory and resources allocated for it.
      67                 :             :  **/
      68                 :             : 
      69                 :             : #define G_DATALIST_FLAGS_MASK_INTERNAL 0x7
      70                 :             : 
      71                 :             : /* When GData.alloc grows to size ALLOC_THRESHOLD_INDEX, we reserve one additional
      72                 :             :  * GHashTable* at &data->data[data->alloc]. This will contain the index for fast
      73                 :             :  * lookup. See datalist_index*() helpers.
      74                 :             :  *
      75                 :             :  * Note that we grow the GData.data buffer by doubling the allocation size. So
      76                 :             :  * we first allocate 64 entries, when adding the 33 entry.
      77                 :             :  *
      78                 :             :  * Conversely, we exponentially shrink the buffer. That means, when we remove
      79                 :             :  * entries and reach 16 (or lower), we will shrink the buffer from 64 to 32
      80                 :             :  * entries (and stop using the index).
      81                 :             :  *
      82                 :             :  * So we start using the index when adding >= 33 entries. And stop using it
      83                 :             :  * when removing to <= 16 entries.
      84                 :             :  */
      85                 :             : #define ALLOC_THRESHOLD_INDEX 64u
      86                 :             : 
      87                 :             : #define G_DATALIST_CLEAN_POINTER(ptr) \
      88                 :             :   ((GData *) ((gpointer) (((guintptr) (ptr)) & ~((guintptr) G_DATALIST_FLAGS_MASK_INTERNAL))))
      89                 :             : 
      90                 :             : /* datalist pointer accesses have to be carried out atomically */
      91                 :             : #define G_DATALIST_GET_POINTER(datalist) \
      92                 :             :   G_DATALIST_CLEAN_POINTER (g_atomic_pointer_get (datalist))
      93                 :             : 
      94                 :             : #define G_DATALIST_SET_POINTER(datalist, pointer)       G_STMT_START {                           \
      95                 :             :   gpointer _oldv = g_atomic_pointer_get (datalist);                                              \
      96                 :             :   gpointer _newv;                                                                                \
      97                 :             :   do {                                                                                           \
      98                 :             :     _newv = (gpointer) (((guintptr) _oldv & ((guintptr) G_DATALIST_FLAGS_MASK_INTERNAL)) | (guintptr) pointer); \
      99                 :             :   } while (!g_atomic_pointer_compare_and_exchange_full ((void**) datalist, _oldv,                \
     100                 :             :                                                         _newv, &_oldv));                         \
     101                 :             : } G_STMT_END
     102                 :             : 
     103                 :             : /* --- structures --- */
     104                 :             : typedef struct {
     105                 :             :   GQuark          key;
     106                 :             :   gpointer        data;
     107                 :             :   GDestroyNotify  destroy;
     108                 :             : } GDataElt;
     109                 :             : 
     110                 :             : typedef struct _GDataset GDataset;
     111                 :             : struct _GData
     112                 :             : {
     113                 :             :   guint32  len;     /* Number of elements */
     114                 :             :   guint32  alloc;   /* Number of allocated elements */
     115                 :             :   GDataElt data[1]; /* Flexible array */
     116                 :             : };
     117                 :             : 
     118                 :             : struct _GDataset
     119                 :             : {
     120                 :             :   gconstpointer location;
     121                 :             :   GData        *datalist;
     122                 :             : };
     123                 :             : 
     124                 :             : 
     125                 :             : /* --- prototypes --- */
     126                 :             : static inline GDataset* g_dataset_lookup                (gconstpointer    dataset_location);
     127                 :             : static void             g_dataset_destroy_internal      (GDataset        *dataset);
     128                 :             : static inline gpointer  g_data_set_internal             (GData          **datalist,
     129                 :             :                                                          GQuark           key_id,
     130                 :             :                                                          gpointer         data,
     131                 :             :                                                          GDestroyNotify   destroy_func,
     132                 :             :                                                          GDataset        *dataset);
     133                 :             : static void             g_data_initialize               (void);
     134                 :             : 
     135                 :             : /* Locking model:
     136                 :             :  * Each standalone GDataList is protected by a bitlock in the datalist pointer,
     137                 :             :  * which protects that modification of the non-flags part of the datalist pointer
     138                 :             :  * and the contents of the datalist.
     139                 :             :  *
     140                 :             :  * For GDataSet we have a global lock g_dataset_global that protects
     141                 :             :  * the global dataset hash and cache, and additionally it protects the
     142                 :             :  * datalist such that we can avoid to use the bit lock in a few places
     143                 :             :  * where it is easy.
     144                 :             :  */
     145                 :             : 
     146                 :             : /* --- variables --- */
     147                 :             : G_LOCK_DEFINE_STATIC (g_dataset_global);
     148                 :             : static GHashTable   *g_dataset_location_ht = NULL;
     149                 :             : static GDataset     *g_dataset_cached = NULL; /* should this be
     150                 :             :                                                  thread specific? */
     151                 :             : 
     152                 :             : /* --- functions --- */
     153                 :             : 
     154                 :             : G_ALWAYS_INLINE static inline GData *
     155                 :             : g_datalist_lock_and_get (GData **datalist)
     156                 :             : {
     157                 :             :   guintptr ptr;
     158                 :             : 
     159                 :    71220607 :   g_pointer_bit_lock_and_get ((void **) datalist, _G_DATALIST_LOCK_BIT, &ptr);
     160                 :    71294988 :   return G_DATALIST_CLEAN_POINTER (ptr);
     161                 :             : }
     162                 :             : 
     163                 :             : static void
     164                 :    21266185 : g_datalist_unlock_and_set (GData **datalist, gpointer ptr)
     165                 :             : {
     166                 :    21266185 :   g_pointer_bit_unlock_and_set ((void **) datalist, _G_DATALIST_LOCK_BIT, ptr, G_DATALIST_FLAGS_MASK_INTERNAL);
     167                 :    21266185 : }
     168                 :             : 
     169                 :             : static gsize
     170                 :    10634023 : datalist_alloc_size (guint32 alloc)
     171                 :             : {
     172                 :             :   /* GDataElt also contains pointer. It thus is suitably aligned for pointers,
     173                 :             :    * and we can just append the pointer for the index at the end. */
     174                 :             :   return G_STRUCT_OFFSET (GData, data) +
     175                 :    10634023 :          (((gsize) alloc) * sizeof (GDataElt)) +
     176                 :    10634023 :          (G_UNLIKELY (alloc >= ALLOC_THRESHOLD_INDEX) ? sizeof (GHashTable *) : 0u);
     177                 :             : }
     178                 :             : 
     179                 :             : G_ALWAYS_INLINE static inline GHashTable **
     180                 :             : datalist_index_get_ptr (GData *data)
     181                 :             : {
     182                 :    58331433 :   if (G_LIKELY (data->alloc < ALLOC_THRESHOLD_INDEX))
     183                 :    77171304 :     return NULL;
     184                 :             : 
     185                 :       20666 :   return (gpointer) (&(data->data[data->alloc]));
     186                 :             : }
     187                 :             : 
     188                 :             : G_ALWAYS_INLINE static inline GHashTable *
     189                 :             : datalist_index_get (GData *data)
     190                 :             : {
     191                 :             :   GHashTable **p_index;
     192                 :             : 
     193                 :    77190623 :   p_index = datalist_index_get_ptr (data);
     194                 :             : 
     195                 :             : #if G_ENABLE_DEBUG
     196                 :    77190623 :   g_assert (!p_index || *p_index);
     197                 :             : #endif
     198                 :             : 
     199                 :    77190623 :   return G_UNLIKELY (p_index) ? *p_index : NULL;
     200                 :             : }
     201                 :             : 
     202                 :             : static guint
     203                 :       25474 : _datalist_index_hash (gconstpointer key)
     204                 :             : {
     205                 :       25474 :   const GQuark *ptr = key;
     206                 :             : 
     207                 :             :   G_STATIC_ASSERT (G_STRUCT_OFFSET (GDataElt, key) == 0);
     208                 :             : 
     209                 :       25474 :   return *ptr;
     210                 :             : }
     211                 :             : 
     212                 :             : static gboolean
     213                 :       13284 : _datalist_index_equal (gconstpointer a, gconstpointer b)
     214                 :             : {
     215                 :       13284 :   const GQuark *ptr_a = a;
     216                 :       13284 :   const GQuark *ptr_b = b;
     217                 :             : 
     218                 :       13284 :   return *ptr_a == *ptr_b;
     219                 :             : }
     220                 :             : 
     221                 :             : G_ALWAYS_INLINE static inline GHashTable *
     222                 :             : datalist_index_new (void)
     223                 :             : {
     224                 :           4 :   return g_hash_table_new (_datalist_index_hash, _datalist_index_equal);
     225                 :             : }
     226                 :             : 
     227                 :             : static GData *
     228                 :        1347 : datalist_realloc (GData *data, guint32 alloc, gboolean *out_reallocated)
     229                 :             : {
     230                 :             :   guintptr data_old;
     231                 :             :   gboolean reallocated;
     232                 :             :   GHashTable *index;
     233                 :             :   GHashTable **p_index;
     234                 :             :   guint32 i;
     235                 :             : 
     236                 :        1347 :   data_old = (guintptr) ((gpointer) data);
     237                 :        1347 :   index = datalist_index_get (data);
     238                 :             : 
     239                 :        1347 :   data = g_realloc (data, datalist_alloc_size (alloc));
     240                 :             : 
     241                 :             :   /* Determine whether realloc() moves the pointer. After a move, the old
     242                 :             :    * pointer would be dangling and comparing it would be undefined behavior.
     243                 :             :    * Avoid that by casting to uintptr_t.
     244                 :             :    */
     245                 :        1347 :   reallocated = (((guintptr) ((gpointer) (data))) != data_old);
     246                 :             : 
     247                 :        1347 :   data->alloc = alloc;
     248                 :             : 
     249                 :        1347 :   if (out_reallocated)
     250                 :        1347 :     *out_reallocated = reallocated;
     251                 :             : 
     252                 :             :   /* Note that if data was @reallocated, then @index contains only dangling pointers.
     253                 :             :    * We can only destroy/remove-all, which we rely on not following those pointers. */
     254                 :             : 
     255                 :        1347 :   p_index = datalist_index_get_ptr (data);
     256                 :             : 
     257                 :        1347 :   if (G_LIKELY (!p_index))
     258                 :             :     {
     259                 :        1322 :       if (G_UNLIKELY (index))
     260                 :           2 :         g_hash_table_unref (index);
     261                 :             :     }
     262                 :          25 :   else if (!reallocated && index)
     263                 :             :     {
     264                 :             :       /* The index is still fine and the pointers are all still valid. We
     265                 :             :        * can keep it. */
     266                 :          10 :       *p_index = index;
     267                 :             :     }
     268                 :             :   else
     269                 :             :     {
     270                 :          15 :       if (G_UNLIKELY (index))
     271                 :             :         {
     272                 :             :           /* Note that the GHashTable's keys are now all dangling pointers!
     273                 :             :            * We rely on remove-all to not following them. */
     274                 :          11 :           g_hash_table_remove_all (index);
     275                 :             :         }
     276                 :             :       else
     277                 :           4 :         index = datalist_index_new ();
     278                 :             : 
     279                 :          15 :       *p_index = index;
     280                 :             : 
     281                 :        2319 :       for (i = 0; i < data->len; i++)
     282                 :        2304 :         g_hash_table_add (index, &data->data[i]);
     283                 :             :     }
     284                 :             : 
     285                 :        1347 :   return data;
     286                 :             : }
     287                 :             : 
     288                 :             : static gboolean
     289                 :    10649660 : datalist_append (GData **data, GQuark key_id, gpointer new_data, GDestroyNotify destroy_func)
     290                 :             : {
     291                 :             :   GDataElt *data_elt;
     292                 :             :   GHashTable *index;
     293                 :             :   gboolean reallocated;
     294                 :             :   GData *d;
     295                 :             : 
     296                 :             : #ifdef G_ENABLE_DEBUG
     297                 :    10649660 :   g_assert (key_id != 0);
     298                 :             : #endif
     299                 :             : 
     300                 :    10649660 :   d = *data;
     301                 :    10649660 :   if (!d)
     302                 :             :     {
     303                 :    10632676 :       d = g_malloc (datalist_alloc_size (2u));
     304                 :    10632676 :       d->len = 0;
     305                 :    10632676 :       d->alloc = 2u;
     306                 :             : 
     307                 :             :       if (2u >= ALLOC_THRESHOLD_INDEX)
     308                 :             :         *(datalist_index_get_ptr (d)) = datalist_index_new ();
     309                 :             : 
     310                 :    10632676 :       *data = d;
     311                 :    10632676 :       reallocated = TRUE;
     312                 :             :     }
     313                 :       16984 :   else if (d->len == d->alloc)
     314                 :             :     {
     315                 :        1293 :       guint32 alloc = d->alloc * 2u;
     316                 :             : 
     317                 :        1293 :       if (G_UNLIKELY (alloc < d->alloc))
     318                 :             :         {
     319                 :           0 :           if (d->alloc == G_MAXUINT32)
     320                 :           0 :             g_error ("GData cannot contain more than 4294967295 entries");
     321                 :           0 :           alloc = G_MAXUINT32;
     322                 :             :         }
     323                 :        1293 :       d = datalist_realloc (d, alloc, &reallocated);
     324                 :        1293 :       *data = d;
     325                 :             :     }
     326                 :             :   else
     327                 :       15691 :     reallocated = FALSE;
     328                 :             : 
     329                 :    10649660 :   data_elt = &d->data[d->len];
     330                 :    10649660 :   *data_elt = (GDataElt){
     331                 :             :     .key = key_id,
     332                 :             :     .data = new_data,
     333                 :             :     .destroy = destroy_func,
     334                 :             :   };
     335                 :    10649660 :   d->len++;
     336                 :             : 
     337                 :    10649660 :   index = datalist_index_get (d);
     338                 :    10649660 :   if (G_UNLIKELY (index))
     339                 :        3350 :     g_hash_table_add (index, data_elt);
     340                 :             : 
     341                 :    10649660 :   return reallocated;
     342                 :             : }
     343                 :             : 
     344                 :             : static void
     345                 :     2426892 : datalist_remove (GData *data, guint32 idx)
     346                 :             : {
     347                 :             :   GHashTable *index;
     348                 :             : 
     349                 :             : #if G_ENABLE_DEBUG
     350                 :     2426892 :   g_assert (idx < data->len);
     351                 :             : #endif
     352                 :             : 
     353                 :             :   /* We remove the element similar to g_array_remove_index_fast(). That is, the
     354                 :             :    * entries up to @idx are left unchanged, and the last entry is moved to
     355                 :             :    * position @idx.
     356                 :             :    */
     357                 :             : 
     358                 :     2426892 :   index = datalist_index_get (data);
     359                 :     2426892 :   if (G_UNLIKELY (index))
     360                 :        3244 :     g_hash_table_remove (index, &data->data[idx]);
     361                 :             : 
     362                 :     2426892 :   data->len--;
     363                 :             : 
     364                 :     2426892 :   if (idx != data->len)
     365                 :             :     {
     366                 :        3045 :       data->data[idx] = data->data[data->len];
     367                 :        3045 :       if (G_UNLIKELY (index))
     368                 :        2554 :         g_hash_table_add (index, &data->data[idx]);
     369                 :             :     }
     370                 :     2426892 : }
     371                 :             : 
     372                 :             : static gboolean
     373                 :     2424834 : datalist_shrink (GData **data, GData **d_to_free)
     374                 :             : {
     375                 :             :   gboolean reallocated;
     376                 :             :   guint32 alloc_by_4;
     377                 :             :   guint32 v;
     378                 :             :   GData *d;
     379                 :             : 
     380                 :     2424834 :   d = *data;
     381                 :             : 
     382                 :     2424834 :   alloc_by_4 = d->alloc / 4u;
     383                 :             : 
     384                 :     2424834 :   if (G_LIKELY (d->len > alloc_by_4))
     385                 :             :     {
     386                 :             :       /* No shrinking */
     387                 :        2023 :       return FALSE;
     388                 :             :     }
     389                 :             : 
     390                 :     2422811 :   if (d->len == 0)
     391                 :             :     {
     392                 :             :       GHashTable *index;
     393                 :             : 
     394                 :             :       /* The list became empty. We drop the allocated memory altogether. */
     395                 :             : 
     396                 :             :       /* The caller will free the buffer after releasing the lock, to minimize
     397                 :             :        * the time we hold the lock. Transfer it out. */
     398                 :             : 
     399                 :     2422757 :       index = datalist_index_get (d);
     400                 :     2422757 :       if (G_UNLIKELY (index))
     401                 :           1 :         g_hash_table_unref (index);
     402                 :             : 
     403                 :     2422757 :       *d_to_free = d;
     404                 :     2422757 :       *data = NULL;
     405                 :     2422757 :       return TRUE;
     406                 :             :     }
     407                 :             : 
     408                 :             :   /* If the buffer is filled not more than 25%. Shrink to double the current length. */
     409                 :             : 
     410                 :          54 :   v = d->len;
     411                 :          54 :   if (v != alloc_by_4)
     412                 :             :     {
     413                 :             :       /* d->alloc is a power of two (unless it's G_MAXUINT32). Usually, we
     414                 :             :        * remove one element at a time, then we will just reach a quarter
     415                 :             :        * of that.
     416                 :             :        *
     417                 :             :        * However, with g_datalist_id_remove_multiple(), len can be smaller
     418                 :             :        * at once. In that case, find first the next power of two. */
     419                 :           2 :       v = g_nearest_pow (v);
     420                 :             :     }
     421                 :          54 :   v *= 2u;
     422                 :             : 
     423                 :             : #if G_ENABLE_DEBUG
     424                 :          54 :   g_assert (v > d->len);
     425                 :          54 :   g_assert (v <= (d->alloc == G_MAXUINT32 ? 0x80000000u : d->alloc / 2u));
     426                 :             : #endif
     427                 :             : 
     428                 :          54 :   d = datalist_realloc (d, v, &reallocated);
     429                 :          54 :   *d_to_free = NULL;
     430                 :          54 :   *data = d;
     431                 :          54 :   return reallocated;
     432                 :             : }
     433                 :             : 
     434                 :             : static void
     435                 :     8209530 : datalist_destroy (GData *data)
     436                 :             : {
     437                 :             :   GHashTable *index;
     438                 :             :   guint32 i;
     439                 :             : 
     440                 :             :   /* Must be called without lock. Will free @data and invoke the
     441                 :             :    * destroy() notifications. */
     442                 :             : 
     443                 :     8209530 :   index = datalist_index_get (data);
     444                 :     8209530 :   if (G_UNLIKELY (index))
     445                 :           1 :     g_hash_table_unref (index);
     446                 :             : 
     447                 :    16431906 :   for (i = 0; i < data->len; i++)
     448                 :             :     {
     449                 :     8222376 :       if (data->data[i].destroy)
     450                 :       10634 :         data->data[i].destroy (data->data[i].data);
     451                 :             :     }
     452                 :             : 
     453                 :     8209530 :   g_free (data);
     454                 :     8209530 : }
     455                 :             : 
     456                 :             : static GDataElt *
     457                 :    64658896 : datalist_find (GData *data, GQuark key_id, guint32 *out_idx)
     458                 :             : {
     459                 :             :   GDataElt *data_elt;
     460                 :             :   GHashTable *index;
     461                 :             :   guint32 i;
     462                 :             : 
     463                 :    64658896 :   if (G_UNLIKELY (!data))
     464                 :    11466517 :     return NULL;
     465                 :             : 
     466                 :    53192379 :   index = datalist_index_get (data);
     467                 :             : 
     468                 :    53192379 :   if (G_LIKELY (!index))
     469                 :             :     {
     470                 :             :       /* We have no index. Do a linear search. */
     471                 :    86093560 :       for (i = 0; i < data->len; i++)
     472                 :             :         {
     473                 :    53237655 :           data_elt = &data->data[i];
     474                 :    53237655 :           if (data_elt->key == key_id)
     475                 :             :             {
     476                 :    20323927 :               if (out_idx)
     477                 :    20251853 :                 *out_idx = i;
     478                 :    20323927 :               return data_elt;
     479                 :             :             }
     480                 :             :         }
     481                 :             : 
     482                 :    32855905 :       return NULL;
     483                 :             :     }
     484                 :             : 
     485                 :       12547 :   data_elt = g_hash_table_lookup (index, &key_id);
     486                 :       12547 :   if (!data_elt)
     487                 :        6535 :     return NULL;
     488                 :             : 
     489                 :             : #if G_ENABLE_DEBUG
     490                 :        6012 :   g_assert (data_elt >= data->data && data_elt < &data->data[data->len]);
     491                 :             : #endif
     492                 :             : 
     493                 :        6012 :   if (out_idx)
     494                 :        4538 :     *out_idx = (data_elt - data->data);
     495                 :        6012 :   return data_elt;
     496                 :             : }
     497                 :             : 
     498                 :             : /**
     499                 :             :  * g_datalist_clear: (skip)
     500                 :             :  * @datalist: a datalist.
     501                 :             :  *
     502                 :             :  * Frees all the data elements of the datalist.
     503                 :             :  * The data elements' destroy functions are called
     504                 :             :  * if they have been set.
     505                 :             :  **/
     506                 :             : void
     507                 :     8209642 : g_datalist_clear (GData **datalist)
     508                 :             : {
     509                 :             :   GData *data;
     510                 :             : 
     511                 :     8209642 :   g_return_if_fail (datalist != NULL);
     512                 :             : 
     513                 :     8209642 :   data = g_datalist_lock_and_get (datalist);
     514                 :             : 
     515                 :     8209642 :   if (!data)
     516                 :             :     {
     517                 :         114 :       g_datalist_unlock (datalist);
     518                 :         114 :       return;
     519                 :             :     }
     520                 :             : 
     521                 :     8209528 :   g_datalist_unlock_and_set (datalist, NULL);
     522                 :             : 
     523                 :     8209528 :   datalist_destroy (data);
     524                 :             : }
     525                 :             : 
     526                 :             : /* HOLDS: g_dataset_global_lock */
     527                 :             : static inline GDataset*
     528                 :          32 : g_dataset_lookup (gconstpointer dataset_location)
     529                 :             : {
     530                 :             :   GDataset *dataset;
     531                 :             :   
     532                 :          32 :   if (g_dataset_cached && g_dataset_cached->location == dataset_location)
     533                 :          14 :     return g_dataset_cached;
     534                 :             :   
     535                 :          18 :   dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
     536                 :          18 :   if (dataset)
     537                 :           7 :     g_dataset_cached = dataset;
     538                 :             :   
     539                 :          18 :   return dataset;
     540                 :             : }
     541                 :             : 
     542                 :             : /* HOLDS: g_dataset_global_lock */
     543                 :             : static void
     544                 :           7 : g_dataset_destroy_internal (GDataset *dataset)
     545                 :             : {
     546                 :             :   gconstpointer dataset_location;
     547                 :             :   
     548                 :           7 :   dataset_location = dataset->location;
     549                 :           9 :   while (dataset)
     550                 :             :     {
     551                 :             :       GData *data;
     552                 :             : 
     553                 :           9 :       data = G_DATALIST_GET_POINTER (&dataset->datalist);
     554                 :             : 
     555                 :           9 :       if (!data)
     556                 :             :         {
     557                 :           7 :           if (dataset == g_dataset_cached)
     558                 :           7 :             g_dataset_cached = NULL;
     559                 :           7 :           g_hash_table_remove (g_dataset_location_ht, dataset_location);
     560                 :           7 :           g_slice_free (GDataset, dataset);
     561                 :           7 :           break;
     562                 :             :         }
     563                 :             : 
     564                 :           2 :       G_DATALIST_SET_POINTER (&dataset->datalist, NULL);
     565                 :             : 
     566                 :           2 :       G_UNLOCK (g_dataset_global);
     567                 :             : 
     568                 :           2 :       datalist_destroy (data);
     569                 :             : 
     570                 :           2 :       G_LOCK (g_dataset_global);
     571                 :           2 :       dataset = g_dataset_lookup (dataset_location);
     572                 :             :     }
     573                 :           7 : }
     574                 :             : 
     575                 :             : /**
     576                 :             :  * g_dataset_destroy:
     577                 :             :  * @dataset_location: (not nullable): the location identifying the dataset.
     578                 :             :  *
     579                 :             :  * Destroys the dataset, freeing all memory allocated, and calling any
     580                 :             :  * destroy functions set for data elements.
     581                 :             :  */
     582                 :             : void
     583                 :           2 : g_dataset_destroy (gconstpointer  dataset_location)
     584                 :             : {
     585                 :           2 :   g_return_if_fail (dataset_location != NULL);
     586                 :             :   
     587                 :           2 :   G_LOCK (g_dataset_global);
     588                 :           2 :   if (g_dataset_location_ht)
     589                 :             :     {
     590                 :             :       GDataset *dataset;
     591                 :             : 
     592                 :           2 :       dataset = g_dataset_lookup (dataset_location);
     593                 :           2 :       if (dataset)
     594                 :           2 :         g_dataset_destroy_internal (dataset);
     595                 :             :     }
     596                 :           2 :   G_UNLOCK (g_dataset_global);
     597                 :             : }
     598                 :             : 
     599                 :             : /* HOLDS: g_dataset_global_lock if dataset != null */
     600                 :             : static inline gpointer
     601                 :       14159 : g_data_set_internal (GData        **datalist,
     602                 :             :                      GQuark         key_id,
     603                 :             :                      gpointer       new_data,
     604                 :             :                      GDestroyNotify new_destroy_func,
     605                 :             :                      GDataset      *dataset)
     606                 :             : {
     607                 :             :   GData *d;
     608                 :       14159 :   GData *new_d = NULL;
     609                 :             :   GDataElt old, *data;
     610                 :             :   guint32 idx;
     611                 :             : 
     612                 :             : #ifdef G_ENABLE_DEBUG
     613                 :       14159 :   g_assert (key_id != 0);
     614                 :             : #endif
     615                 :             : 
     616                 :       14159 :   d = g_datalist_lock_and_get (datalist);
     617                 :             : 
     618                 :       14159 :   data = datalist_find (d, key_id, &idx);
     619                 :             : 
     620                 :       14159 :   if (new_data == NULL) /* remove */
     621                 :             :     {
     622                 :        5051 :       if (data)
     623                 :             :         {
     624                 :             :           GData *d_to_free;
     625                 :             : 
     626                 :        1229 :           old = *data;
     627                 :             : 
     628                 :        1229 :           datalist_remove (d, idx);
     629                 :        1229 :           if (datalist_shrink (&d, &d_to_free))
     630                 :             :             {
     631                 :          15 :               g_datalist_unlock_and_set (datalist, d);
     632                 :             : 
     633                 :             :               /* the dataset destruction *must* be done
     634                 :             :                * prior to invocation of the data destroy function
     635                 :             :                */
     636                 :          15 :               if (dataset && !d)
     637                 :           5 :                 g_dataset_destroy_internal (dataset);
     638                 :             : 
     639                 :          15 :               if (G_UNLIKELY (d_to_free))
     640                 :          15 :                 g_free (d_to_free);
     641                 :             :             }
     642                 :             :           else
     643                 :        1214 :             g_datalist_unlock (datalist);
     644                 :             : 
     645                 :             :           /* We found and removed an old value
     646                 :             :            * the GData struct *must* already be unlinked
     647                 :             :            * when invoking the destroy function.
     648                 :             :            * we use (new_data==NULL && new_destroy_func!=NULL) as
     649                 :             :            * a special hint combination to "steal"
     650                 :             :            * data without destroy notification
     651                 :             :            */
     652                 :        1229 :           if (old.destroy && !new_destroy_func)
     653                 :             :             {
     654                 :           7 :               if (dataset)
     655                 :           2 :                 G_UNLOCK (g_dataset_global);
     656                 :           7 :               old.destroy (old.data);
     657                 :           7 :               if (dataset)
     658                 :           2 :                 G_LOCK (g_dataset_global);
     659                 :           7 :               old.data = NULL;
     660                 :             :             }
     661                 :             : 
     662                 :        1229 :           return old.data;
     663                 :             :         }
     664                 :             :     }
     665                 :             :   else
     666                 :             :     {
     667                 :        9108 :       if (data)
     668                 :             :         {
     669                 :        1411 :           if (!data->destroy)
     670                 :             :             {
     671                 :        1297 :               data->data = new_data;
     672                 :        1297 :               data->destroy = new_destroy_func;
     673                 :        1297 :               g_datalist_unlock (datalist);
     674                 :             :             }
     675                 :             :           else
     676                 :             :             {
     677                 :         114 :               old = *data;
     678                 :         114 :               data->data = new_data;
     679                 :         114 :               data->destroy = new_destroy_func;
     680                 :             : 
     681                 :         114 :               g_datalist_unlock (datalist);
     682                 :             : 
     683                 :             :               /* We found and replaced an old value
     684                 :             :                * the GData struct *must* already be unlinked
     685                 :             :                * when invoking the destroy function.
     686                 :             :                */
     687                 :         114 :               if (dataset)
     688                 :           0 :                 G_UNLOCK (g_dataset_global);
     689                 :         114 :               old.destroy (old.data);
     690                 :         114 :               if (dataset)
     691                 :           0 :                 G_LOCK (g_dataset_global);
     692                 :             :             }
     693                 :        1411 :           return NULL;
     694                 :             :         }
     695                 :             : 
     696                 :             :       /* The key was not found, insert it */
     697                 :        7697 :       if (datalist_append (&d, key_id, new_data, new_destroy_func))
     698                 :        3218 :         new_d = d;
     699                 :             :     }
     700                 :             : 
     701                 :       11519 :   if (new_d)
     702                 :        3218 :     g_datalist_unlock_and_set (datalist, new_d);
     703                 :             :   else
     704                 :        8301 :     g_datalist_unlock (datalist);
     705                 :             : 
     706                 :       11519 :   return NULL;
     707                 :             : 
     708                 :             : }
     709                 :             : 
     710                 :             : /**
     711                 :             :  * g_datalist_id_remove_multiple:
     712                 :             :  * @datalist: a datalist
     713                 :             :  * @keys: (array length=n_keys): keys to remove
     714                 :             :  * @n_keys: length of @keys.
     715                 :             :  *
     716                 :             :  * Removes multiple keys from a datalist.
     717                 :             :  *
     718                 :             :  * This is more efficient than calling g_datalist_id_remove_data()
     719                 :             :  * multiple times in a row.
     720                 :             :  *
     721                 :             :  * Before 2.80, @n_keys had to be not larger than 16.
     722                 :             :  * Since 2.84, performance is improved for larger number of keys.
     723                 :             :  *
     724                 :             :  * Since: 2.74
     725                 :             :  */
     726                 :             : void
     727                 :           8 : g_datalist_id_remove_multiple (GData **datalist,
     728                 :             :                                GQuark *keys,
     729                 :             :                                gsize n_keys)
     730                 :             : {
     731                 :             :   GData *d;
     732                 :             :   GDataElt *old;
     733                 :           8 :   GDataElt *old_to_free = NULL;
     734                 :             :   GData *d_to_free;
     735                 :             :   gsize found_keys;
     736                 :             :   gsize i_keys;
     737                 :             : 
     738                 :           8 :   if (n_keys == 0)
     739                 :           0 :     return;
     740                 :             : 
     741                 :           8 :   d = g_datalist_lock_and_get (datalist);
     742                 :             : 
     743                 :           8 :   if (!d)
     744                 :             :     {
     745                 :           0 :       g_datalist_unlock (datalist);
     746                 :           0 :       return;
     747                 :             :     }
     748                 :             : 
     749                 :             :   /* Allocate an array of GDataElt to hold copies of the elements
     750                 :             :    * that are removed from the datalist. Allow enough space for all
     751                 :             :    * the keys.
     752                 :             :    *
     753                 :             :    * At most allocate 400 bytes on the stack. Especially since we call
     754                 :             :    * out to external code, we don't know how much stack we can use. */
     755                 :           8 :   if (n_keys <= 400u / sizeof (GDataElt))
     756                 :           2 :     old = g_newa (GDataElt, n_keys);
     757                 :             :   else
     758                 :             :     {
     759                 :           6 :       old_to_free = g_new (GDataElt, n_keys);
     760                 :           6 :       old = old_to_free;
     761                 :             :     }
     762                 :             : 
     763                 :           8 :   found_keys = 0;
     764                 :        3576 :   for (i_keys = 0; i_keys < n_keys; i_keys++)
     765                 :             :     {
     766                 :             :       GDataElt *data_elt;
     767                 :             :       guint32 idx;
     768                 :             : 
     769                 :        3568 :       data_elt = datalist_find (d, keys[i_keys], &idx);
     770                 :        3568 :       if (!data_elt)
     771                 :        1502 :         continue;
     772                 :             : 
     773                 :             :       /* We must destroy the keys in the order in which they are specified.
     774                 :             :        * We achieve that here.
     775                 :             :        *
     776                 :             :        * Note that even if @keys contains duplicates, we correctly only
     777                 :             :        * find them once, as we remove the found entry right away. */
     778                 :        2066 :       old[found_keys++] = *data_elt;
     779                 :        2066 :       datalist_remove (d, idx);
     780                 :             :     }
     781                 :             : 
     782                 :           8 :   if (found_keys > 0 && datalist_shrink (&d, &d_to_free))
     783                 :             :     {
     784                 :           3 :       g_datalist_unlock_and_set (datalist, d);
     785                 :           3 :       if (G_UNLIKELY (d_to_free))
     786                 :           3 :         g_free (d_to_free);
     787                 :             :     }
     788                 :             :   else
     789                 :           5 :     g_datalist_unlock (datalist);
     790                 :             : 
     791                 :        2074 :   for (i_keys = 0; i_keys < found_keys; i_keys++)
     792                 :             :     {
     793                 :        2066 :       if (old[i_keys].destroy)
     794                 :           3 :         old[i_keys].destroy (old[i_keys].data);
     795                 :             :     }
     796                 :             : 
     797                 :           8 :   if (G_UNLIKELY (old_to_free))
     798                 :           6 :     g_free (old_to_free);
     799                 :             : }
     800                 :             : 
     801                 :             : /**
     802                 :             :  * g_dataset_id_set_data_full: (skip)
     803                 :             :  * @dataset_location: (not nullable): the location identifying the dataset.
     804                 :             :  * @key_id: the #GQuark id to identify the data element.
     805                 :             :  * @data: the data element.
     806                 :             :  * @destroy_func: the function to call when the data element is
     807                 :             :  *                removed. This function will be called with the data
     808                 :             :  *                element and can be used to free any memory allocated
     809                 :             :  *                for it.
     810                 :             :  *
     811                 :             :  * Sets the data element associated with the given #GQuark id, and also
     812                 :             :  * the function to call when the data element is destroyed. Any
     813                 :             :  * previous data with the same key is removed, and its destroy function
     814                 :             :  * is called.
     815                 :             :  **/
     816                 :             : /**
     817                 :             :  * g_dataset_set_data_full: (skip)
     818                 :             :  * @l: the location identifying the dataset.
     819                 :             :  * @k: the string to identify the data element.
     820                 :             :  * @d: the data element.
     821                 :             :  * @f: the function to call when the data element is removed. This
     822                 :             :  *     function will be called with the data element and can be used to
     823                 :             :  *     free any memory allocated for it.
     824                 :             :  *
     825                 :             :  * Sets the data corresponding to the given string identifier, and the
     826                 :             :  * function to call when the data element is destroyed.
     827                 :             :  **/
     828                 :             : /**
     829                 :             :  * g_dataset_id_set_data:
     830                 :             :  * @l: the location identifying the dataset.
     831                 :             :  * @k: the #GQuark id to identify the data element.
     832                 :             :  * @d: the data element.
     833                 :             :  *
     834                 :             :  * Sets the data element associated with the given #GQuark id. Any
     835                 :             :  * previous data with the same key is removed, and its destroy function
     836                 :             :  * is called.
     837                 :             :  **/
     838                 :             : /**
     839                 :             :  * g_dataset_set_data:
     840                 :             :  * @l: the location identifying the dataset.
     841                 :             :  * @k: the string to identify the data element.
     842                 :             :  * @d: the data element.
     843                 :             :  *
     844                 :             :  * Sets the data corresponding to the given string identifier.
     845                 :             :  **/
     846                 :             : /**
     847                 :             :  * g_dataset_id_remove_data:
     848                 :             :  * @l: the location identifying the dataset.
     849                 :             :  * @k: the #GQuark id identifying the data element.
     850                 :             :  *
     851                 :             :  * Removes a data element from a dataset. The data element's destroy
     852                 :             :  * function is called if it has been set.
     853                 :             :  **/
     854                 :             : /**
     855                 :             :  * g_dataset_remove_data:
     856                 :             :  * @l: the location identifying the dataset.
     857                 :             :  * @k: the string identifying the data element.
     858                 :             :  *
     859                 :             :  * Removes a data element corresponding to a string. Its destroy
     860                 :             :  * function is called if it has been set.
     861                 :             :  **/
     862                 :             : void
     863                 :          17 : g_dataset_id_set_data_full (gconstpointer  dataset_location,
     864                 :             :                             GQuark         key_id,
     865                 :             :                             gpointer       data,
     866                 :             :                             GDestroyNotify destroy_func)
     867                 :             : {
     868                 :             :   GDataset *dataset;
     869                 :             :   
     870                 :          17 :   g_return_if_fail (dataset_location != NULL);
     871                 :          17 :   if (!data)
     872                 :           4 :     g_return_if_fail (destroy_func == NULL);
     873                 :          17 :   if (!key_id)
     874                 :             :     {
     875                 :           0 :       if (data)
     876                 :           0 :         g_return_if_fail (key_id > 0);
     877                 :             :       else
     878                 :           0 :         return;
     879                 :             :     }
     880                 :             :   
     881                 :          17 :   G_LOCK (g_dataset_global);
     882                 :          17 :   if (!g_dataset_location_ht)
     883                 :           1 :     g_data_initialize ();
     884                 :             :  
     885                 :          17 :   dataset = g_dataset_lookup (dataset_location);
     886                 :          17 :   if (!dataset)
     887                 :             :     {
     888                 :           7 :       dataset = g_slice_new (GDataset);
     889                 :           7 :       dataset->location = dataset_location;
     890                 :           7 :       g_datalist_init (&dataset->datalist);
     891                 :           7 :       g_hash_table_insert (g_dataset_location_ht, 
     892                 :           7 :                            (gpointer) dataset->location,
     893                 :             :                            dataset);
     894                 :             :     }
     895                 :             :   
     896                 :          17 :   g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
     897                 :          17 :   G_UNLOCK (g_dataset_global);
     898                 :             : }
     899                 :             : 
     900                 :             : /**
     901                 :             :  * g_datalist_id_set_data_full: (skip)
     902                 :             :  * @datalist: a datalist.
     903                 :             :  * @key_id: the #GQuark to identify the data element.
     904                 :             :  * @data: (nullable): the data element or %NULL to remove any previous element
     905                 :             :  *        corresponding to @key_id.
     906                 :             :  * @destroy_func: (nullable): the function to call when the data element is
     907                 :             :  *                removed. This function will be called with the data
     908                 :             :  *                element and can be used to free any memory allocated
     909                 :             :  *                for it. If @data is %NULL, then @destroy_func must
     910                 :             :  *                also be %NULL.
     911                 :             :  *
     912                 :             :  * Sets the data corresponding to the given #GQuark id, and the
     913                 :             :  * function to be called when the element is removed from the datalist.
     914                 :             :  * Any previous data with the same key is removed, and its destroy
     915                 :             :  * function is called.
     916                 :             :  **/
     917                 :             : /**
     918                 :             :  * g_datalist_set_data_full: (skip)
     919                 :             :  * @dl: a datalist.
     920                 :             :  * @k: the string to identify the data element.
     921                 :             :  * @d: (nullable): the data element, or %NULL to remove any previous element
     922                 :             :  *     corresponding to @k.
     923                 :             :  * @f: (nullable): the function to call when the data element is removed.
     924                 :             :  *     This function will be called with the data element and can be used to
     925                 :             :  *     free any memory allocated for it. If @d is %NULL, then @f must
     926                 :             :  *     also be %NULL.
     927                 :             :  *
     928                 :             :  * Sets the data element corresponding to the given string identifier,
     929                 :             :  * and the function to be called when the data element is removed.
     930                 :             :  **/
     931                 :             : /**
     932                 :             :  * g_datalist_id_set_data:
     933                 :             :  * @dl: a datalist.
     934                 :             :  * @q: the #GQuark to identify the data element.
     935                 :             :  * @d: (nullable): the data element, or %NULL to remove any previous element
     936                 :             :  *     corresponding to @q.
     937                 :             :  *
     938                 :             :  * Sets the data corresponding to the given #GQuark id. Any previous
     939                 :             :  * data with the same key is removed, and its destroy function is
     940                 :             :  * called.
     941                 :             :  **/
     942                 :             : /**
     943                 :             :  * g_datalist_set_data:
     944                 :             :  * @dl: a datalist.
     945                 :             :  * @k: the string to identify the data element.
     946                 :             :  * @d: (nullable): the data element, or %NULL to remove any previous element
     947                 :             :  *     corresponding to @k.
     948                 :             :  *
     949                 :             :  * Sets the data element corresponding to the given string identifier.
     950                 :             :  **/
     951                 :             : /**
     952                 :             :  * g_datalist_id_remove_data:
     953                 :             :  * @dl: a datalist.
     954                 :             :  * @q: the #GQuark identifying the data element.
     955                 :             :  *
     956                 :             :  * Removes an element, using its #GQuark identifier.
     957                 :             :  **/
     958                 :             : /**
     959                 :             :  * g_datalist_remove_data:
     960                 :             :  * @dl: a datalist.
     961                 :             :  * @k: the string identifying the data element.
     962                 :             :  *
     963                 :             :  * Removes an element using its string identifier. The data element's
     964                 :             :  * destroy function is called if it has been set.
     965                 :             :  **/
     966                 :             : void
     967                 :       14205 : g_datalist_id_set_data_full (GData        **datalist,
     968                 :             :                              GQuark         key_id,
     969                 :             :                              gpointer       data,
     970                 :             :                              GDestroyNotify destroy_func)
     971                 :             : {
     972                 :       14205 :   g_return_if_fail (datalist != NULL);
     973                 :       14205 :   if (!data)
     974                 :        5110 :     g_return_if_fail (destroy_func == NULL);
     975                 :       14205 :   if (!key_id)
     976                 :             :     {
     977                 :          67 :       if (data)
     978                 :           0 :         g_return_if_fail (key_id > 0);
     979                 :             :       else
     980                 :          67 :         return;
     981                 :             :     }
     982                 :             : 
     983                 :       14138 :   g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
     984                 :             : }
     985                 :             : 
     986                 :             : /**
     987                 :             :  * g_dataset_id_remove_no_notify: (skip)
     988                 :             :  * @dataset_location: (not nullable): the location identifying the dataset.
     989                 :             :  * @key_id: the #GQuark ID identifying the data element.
     990                 :             :  *
     991                 :             :  * Removes an element, without calling its destroy notification
     992                 :             :  * function.
     993                 :             :  *
     994                 :             :  * Returns: (nullable): the data previously stored at @key_id,
     995                 :             :  *          or %NULL if none.
     996                 :             :  **/
     997                 :             : /**
     998                 :             :  * g_dataset_remove_no_notify: (skip)
     999                 :             :  * @l: the location identifying the dataset.
    1000                 :             :  * @k: the string identifying the data element.
    1001                 :             :  *
    1002                 :             :  * Removes an element, without calling its destroy notifier.
    1003                 :             :  **/
    1004                 :             : gpointer
    1005                 :           1 : g_dataset_id_remove_no_notify (gconstpointer  dataset_location,
    1006                 :             :                                GQuark         key_id)
    1007                 :             : {
    1008                 :           1 :   gpointer ret_data = NULL;
    1009                 :             : 
    1010                 :           1 :   g_return_val_if_fail (dataset_location != NULL, NULL);
    1011                 :             :   
    1012                 :           1 :   if (key_id == 0)
    1013                 :           0 :     return NULL;
    1014                 :             : 
    1015                 :           1 :   G_LOCK (g_dataset_global);
    1016                 :           1 :   if (g_dataset_location_ht)
    1017                 :             :     {
    1018                 :             :       GDataset *dataset;
    1019                 :             :   
    1020                 :           1 :       dataset = g_dataset_lookup (dataset_location);
    1021                 :           1 :       if (dataset)
    1022                 :           1 :         ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
    1023                 :             :     } 
    1024                 :           1 :   G_UNLOCK (g_dataset_global);
    1025                 :             : 
    1026                 :           1 :   return ret_data;
    1027                 :             : }
    1028                 :             : 
    1029                 :             : /**
    1030                 :             :  * g_datalist_id_remove_no_notify: (skip)
    1031                 :             :  * @datalist: a datalist.
    1032                 :             :  * @key_id: the #GQuark identifying a data element.
    1033                 :             :  *
    1034                 :             :  * Removes an element, without calling its destroy notification
    1035                 :             :  * function.
    1036                 :             :  *
    1037                 :             :  * Returns: (nullable): the data previously stored at @key_id,
    1038                 :             :  *          or %NULL if none.
    1039                 :             :  **/
    1040                 :             : /**
    1041                 :             :  * g_datalist_remove_no_notify: (skip)
    1042                 :             :  * @dl: a datalist.
    1043                 :             :  * @k: the string identifying the data element.
    1044                 :             :  *
    1045                 :             :  * Removes an element, without calling its destroy notifier.
    1046                 :             :  **/
    1047                 :             : gpointer
    1048                 :           3 : g_datalist_id_remove_no_notify (GData   **datalist,
    1049                 :             :                                 GQuark    key_id)
    1050                 :             : {
    1051                 :           3 :   gpointer ret_data = NULL;
    1052                 :             : 
    1053                 :           3 :   g_return_val_if_fail (datalist != NULL, NULL);
    1054                 :             : 
    1055                 :           3 :   if (key_id)
    1056                 :           3 :     ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
    1057                 :             : 
    1058                 :           3 :   return ret_data;
    1059                 :             : }
    1060                 :             : 
    1061                 :             : /*< private >
    1062                 :             :  * g_datalist_id_update_atomic:
    1063                 :             :  * @datalist: the data list
    1064                 :             :  * @key_id: the key to add.
    1065                 :             :  * @already_locked: whether the GData lock is already held.
    1066                 :             :  * @callback: (scope call): callback to update (set, remove, steal, update) the
    1067                 :             :  *   data.
    1068                 :             :  * @user_data: the user data for @callback.
    1069                 :             :  *
    1070                 :             :  * Will call @callback while holding the lock on @datalist. Be careful to not
    1071                 :             :  * end up calling into another data-list function, because the lock is not
    1072                 :             :  * reentrant and deadlock will happen.
    1073                 :             :  *
    1074                 :             :  * The callback receives the current data and destroy function. If @key_id is
    1075                 :             :  * currently not in @datalist, they will be %NULL. The callback can update
    1076                 :             :  * those pointers, and @datalist will be updated with the result. Note that if
    1077                 :             :  * callback modifies a received data, then it MUST steal it and take ownership
    1078                 :             :  * on it. Possibly by freeing it with the provided destroy function.
    1079                 :             :  *
    1080                 :             :  * The point is to atomically access the entry, while holding a lock
    1081                 :             :  * of @datalist. Without this, the user would have to hold their own mutex
    1082                 :             :  * while handling @key_id entry.
    1083                 :             :  *
    1084                 :             :  * The return value of @callback is not used, except it becomes the return
    1085                 :             :  * value of the function. This is an alternative to returning a result via
    1086                 :             :  * @user_data.
    1087                 :             :  *
    1088                 :             :  * If @already_locked is TRUE, the caller previously already called
    1089                 :             :  * g_datalist_lock(). In that case, g_datalist_id_update_atomic() assumes it
    1090                 :             :  * already holds the lock and does not take the lock again. Note that in any
    1091                 :             :  * case, at the end g_datalist_id_update_atomic() will always unlock the GData.
    1092                 :             :  * This asymmetry is here, because update may reallocate the buffer and it is
    1093                 :             :  * more efficient to do when releasing the lock. The few callers that set
    1094                 :             :  * @already_locked to TRUE are fine with this asymmetry and anyway want to
    1095                 :             :  * unlock afterwards.
    1096                 :             :  *
    1097                 :             :  * Returns: the value returned by @callback.
    1098                 :             :  */
    1099                 :             : gpointer
    1100                 :    64337443 : g_datalist_id_update_atomic (GData **datalist,
    1101                 :             :                              GQuark key_id,
    1102                 :             :                              gboolean already_locked,
    1103                 :             :                              GDataListUpdateAtomicFunc callback,
    1104                 :             :                              gpointer user_data)
    1105                 :             : {
    1106                 :             :   GData *d;
    1107                 :             :   GDataElt *data;
    1108                 :             :   gpointer new_data;
    1109                 :             :   gpointer result;
    1110                 :             :   GDestroyNotify new_destroy;
    1111                 :             :   guint32 idx;
    1112                 :             : 
    1113                 :    64337443 :   g_return_val_if_fail (datalist, NULL);
    1114                 :    64337443 :   g_return_val_if_fail (key_id != 0, NULL);
    1115                 :             : 
    1116                 :    64337443 :   if (G_UNLIKELY (already_locked))
    1117                 :             :     {
    1118                 :     1858408 :       d = G_DATALIST_GET_POINTER (datalist);
    1119                 :             :     }
    1120                 :             :   else
    1121                 :             :     {
    1122                 :    62479035 :       d = g_datalist_lock_and_get (datalist);
    1123                 :             :     }
    1124                 :             : 
    1125                 :    64337443 :   data = datalist_find (d, key_id, &idx);
    1126                 :             : 
    1127                 :    64337443 :   if (data)
    1128                 :             :     {
    1129                 :    20022342 :       new_data = data->data;
    1130                 :    20022342 :       new_destroy = data->destroy;
    1131                 :             :     }
    1132                 :             :   else
    1133                 :             :     {
    1134                 :    44315101 :       new_data = NULL;
    1135                 :    44315101 :       new_destroy = NULL;
    1136                 :             :     }
    1137                 :             : 
    1138                 :    64337443 :   result = callback (&new_data, &new_destroy, user_data);
    1139                 :             : 
    1140                 :    64337443 :   if (G_LIKELY (data))
    1141                 :             :     {
    1142                 :    20022342 :       if (G_LIKELY (data->data == new_data && data->destroy == new_destroy))
    1143                 :             :         {
    1144                 :             :           /* No change. */
    1145                 :             :         }
    1146                 :     4746461 :       else if (!new_data)
    1147                 :             :         {
    1148                 :             :           GData *d_to_free;
    1149                 :             : 
    1150                 :             :           /* Remove. The callback indicates to drop the entry.
    1151                 :             :            *
    1152                 :             :            * The old data->data was stolen by callback(). */
    1153                 :     2423596 :           datalist_remove (d, idx);
    1154                 :     2423596 :           if (datalist_shrink (&d, &d_to_free))
    1155                 :             :             {
    1156                 :     2422738 :               g_datalist_unlock_and_set (datalist, d);
    1157                 :     2422738 :               if (G_UNLIKELY (d_to_free))
    1158                 :     2422738 :                 g_free (d_to_free);
    1159                 :     2422738 :               goto return_without_unlock;
    1160                 :             :             }
    1161                 :             :         }
    1162                 :             :       else
    1163                 :             :         {
    1164                 :             :           /* Update. The callback may have provided new pointers to an existing
    1165                 :             :            * entry.
    1166                 :             :            *
    1167                 :             :            * The old data was stolen by callback(). We only update the pointers and
    1168                 :             :            * are done. */
    1169                 :     2322865 :           data->data = new_data;
    1170                 :     2322865 :           data->destroy = new_destroy;
    1171                 :             :         }
    1172                 :             :     }
    1173                 :             :   else
    1174                 :             :     {
    1175                 :    44315101 :       if (G_LIKELY (!new_data))
    1176                 :             :         {
    1177                 :             :           /* No change. The entry didn't exist and still does not. */
    1178                 :             :         }
    1179                 :             :       else
    1180                 :             :         {
    1181                 :             :           /* Add. Add a new entry that didn't exist previously. */
    1182                 :    10641961 :           if (datalist_append (&d, key_id, new_data, new_destroy))
    1183                 :             :             {
    1184                 :    10630680 :               g_datalist_unlock_and_set (datalist, d);
    1185                 :    10630680 :               goto return_without_unlock;
    1186                 :             :             }
    1187                 :             :         }
    1188                 :             :     }
    1189                 :             : 
    1190                 :    51284025 :   g_datalist_unlock (datalist);
    1191                 :             : 
    1192                 :    64337443 : return_without_unlock:
    1193                 :    64337443 :   return result;
    1194                 :             : }
    1195                 :             : 
    1196                 :             : /**
    1197                 :             :  * g_dataset_id_get_data:
    1198                 :             :  * @dataset_location: (not nullable): the location identifying the dataset.
    1199                 :             :  * @key_id: the #GQuark id to identify the data element.
    1200                 :             :  *
    1201                 :             :  * Gets the data element corresponding to a #GQuark.
    1202                 :             :  *
    1203                 :             :  * Returns: (transfer none) (nullable): the data element corresponding to
    1204                 :             :  *          the #GQuark, or %NULL if it is not found.
    1205                 :             :  **/
    1206                 :             : /**
    1207                 :             :  * g_dataset_get_data:
    1208                 :             :  * @l: the location identifying the dataset.
    1209                 :             :  * @k: the string identifying the data element.
    1210                 :             :  *
    1211                 :             :  * Gets the data element corresponding to a string.
    1212                 :             :  *
    1213                 :             :  * Returns: (transfer none) (nullable): the data element corresponding to
    1214                 :             :  *          the string, or %NULL if it is not found.
    1215                 :             :  **/
    1216                 :             : gpointer
    1217                 :          12 : g_dataset_id_get_data (gconstpointer  dataset_location,
    1218                 :             :                        GQuark         key_id)
    1219                 :             : {
    1220                 :          12 :   gpointer retval = NULL;
    1221                 :             : 
    1222                 :          12 :   g_return_val_if_fail (dataset_location != NULL, NULL);
    1223                 :             : 
    1224                 :          12 :   if (key_id == 0)
    1225                 :           3 :     return NULL;
    1226                 :             : 
    1227                 :           9 :   G_LOCK (g_dataset_global);
    1228                 :           9 :   if (g_dataset_location_ht)
    1229                 :             :     {
    1230                 :             :       GDataset *dataset;
    1231                 :             :       
    1232                 :           9 :       dataset = g_dataset_lookup (dataset_location);
    1233                 :           9 :       if (dataset)
    1234                 :           5 :         retval = g_datalist_id_get_data (&dataset->datalist, key_id);
    1235                 :             :     }
    1236                 :           9 :   G_UNLOCK (g_dataset_global);
    1237                 :             :  
    1238                 :           9 :   return retval;
    1239                 :             : }
    1240                 :             : 
    1241                 :             : /**
    1242                 :             :  * g_datalist_id_get_data:
    1243                 :             :  * @datalist: a datalist.
    1244                 :             :  * @key_id: the #GQuark identifying a data element.
    1245                 :             :  *
    1246                 :             :  * Retrieves the data element corresponding to @key_id.
    1247                 :             :  *
    1248                 :             :  * Returns: (transfer none) (nullable): the data element, or %NULL if
    1249                 :             :  *          it is not found.
    1250                 :             :  */
    1251                 :             : gpointer
    1252                 :       74378 : g_datalist_id_get_data (GData  **datalist,
    1253                 :             :                         GQuark   key_id)
    1254                 :             : {
    1255                 :       74378 :   return g_datalist_id_dup_data (datalist, key_id, NULL, NULL);
    1256                 :             : }
    1257                 :             : 
    1258                 :             : /**
    1259                 :             :  * GDuplicateFunc:
    1260                 :             :  * @data: the data to duplicate
    1261                 :             :  * @user_data: (closure): user data that was specified in
    1262                 :             :  *             g_datalist_id_dup_data()
    1263                 :             :  *
    1264                 :             :  * The type of functions that are used to 'duplicate' an object.
    1265                 :             :  * What this means depends on the context, it could just be
    1266                 :             :  * incrementing the reference count, if @data is a ref-counted
    1267                 :             :  * object.
    1268                 :             :  *
    1269                 :             :  * Returns: a duplicate of data
    1270                 :             :  */
    1271                 :             : 
    1272                 :             : /**
    1273                 :             :  * g_datalist_id_dup_data: (skip)
    1274                 :             :  * @datalist: location of a datalist
    1275                 :             :  * @key_id: the #GQuark identifying a data element
    1276                 :             :  * @dup_func: (scope call) (closure user_data) (nullable): function to
    1277                 :             :  *   duplicate the old value
    1278                 :             :  * @user_data: passed as user_data to @dup_func
    1279                 :             :  *
    1280                 :             :  * This is a variant of g_datalist_id_get_data() which
    1281                 :             :  * returns a 'duplicate' of the value. @dup_func defines the
    1282                 :             :  * meaning of 'duplicate' in this context, it could e.g.
    1283                 :             :  * take a reference on a ref-counted object.
    1284                 :             :  *
    1285                 :             :  * If the @key_id is not set in the datalist then @dup_func
    1286                 :             :  * will be called with a %NULL argument.
    1287                 :             :  *
    1288                 :             :  * Note that @dup_func is called while the datalist is locked, so it
    1289                 :             :  * is not allowed to read or modify the datalist.
    1290                 :             :  *
    1291                 :             :  * This function can be useful to avoid races when multiple
    1292                 :             :  * threads are using the same datalist and the same key.
    1293                 :             :  *
    1294                 :             :  * Returns: (nullable): the result of calling @dup_func on the value
    1295                 :             :  *     associated with @key_id in @datalist, or %NULL if not set.
    1296                 :             :  *     If @dup_func is %NULL, the value is returned unmodified.
    1297                 :             :  *
    1298                 :             :  * Since: 2.34
    1299                 :             :  */
    1300                 :             : gpointer
    1301                 :       74381 : g_datalist_id_dup_data (GData          **datalist,
    1302                 :             :                         GQuark           key_id,
    1303                 :             :                         GDuplicateFunc   dup_func,
    1304                 :             :                         gpointer         user_data)
    1305                 :             : {
    1306                 :       74381 :   gpointer val = NULL;
    1307                 :       74381 :   gpointer retval = NULL;
    1308                 :             :   GData *d;
    1309                 :             :   GDataElt *data;
    1310                 :             : 
    1311                 :       74381 :   d = g_datalist_lock_and_get (datalist);
    1312                 :             : 
    1313                 :       74381 :   data = datalist_find (d, key_id, NULL);
    1314                 :       74381 :   if (data)
    1315                 :       73548 :     val = data->data;
    1316                 :             : 
    1317                 :       74381 :   if (dup_func)
    1318                 :           3 :     retval = dup_func (val, user_data);
    1319                 :             :   else
    1320                 :       74378 :     retval = val;
    1321                 :             : 
    1322                 :       74381 :   g_datalist_unlock (datalist);
    1323                 :             : 
    1324                 :       74381 :   return retval;
    1325                 :             : }
    1326                 :             : 
    1327                 :             : /**
    1328                 :             :  * g_datalist_id_replace_data: (skip)
    1329                 :             :  * @datalist: location of a datalist
    1330                 :             :  * @key_id: the #GQuark identifying a data element
    1331                 :             :  * @oldval: (nullable): the old value to compare against
    1332                 :             :  * @newval: (nullable): the new value to replace it with
    1333                 :             :  * @destroy: (nullable): destroy notify for the new value
    1334                 :             :  * @old_destroy: (out) (optional): destroy notify for the existing value
    1335                 :             :  *
    1336                 :             :  * Compares the member that is associated with @key_id in
    1337                 :             :  * @datalist to @oldval, and if they are the same, replace
    1338                 :             :  * @oldval with @newval.
    1339                 :             :  *
    1340                 :             :  * This is like a typical atomic compare-and-exchange
    1341                 :             :  * operation, for a member of @datalist.
    1342                 :             :  *
    1343                 :             :  * If the previous value was replaced then ownership of the
    1344                 :             :  * old value (@oldval) is passed to the caller, including
    1345                 :             :  * the registered destroy notify for it (passed out in @old_destroy).
    1346                 :             :  * Its up to the caller to free this as they wish, which may
    1347                 :             :  * or may not include using @old_destroy as sometimes replacement
    1348                 :             :  * should not destroy the object in the normal way.
    1349                 :             :  *
    1350                 :             :  * Returns: %TRUE if the existing value for @key_id was replaced
    1351                 :             :  *  by @newval, %FALSE otherwise.
    1352                 :             :  *
    1353                 :             :  * Since: 2.34
    1354                 :             :  */
    1355                 :             : gboolean
    1356                 :      229345 : g_datalist_id_replace_data (GData          **datalist,
    1357                 :             :                             GQuark           key_id,
    1358                 :             :                             gpointer         oldval,
    1359                 :             :                             gpointer         newval,
    1360                 :             :                             GDestroyNotify   destroy,
    1361                 :             :                             GDestroyNotify  *old_destroy)
    1362                 :             : {
    1363                 :      229345 :   gpointer val = NULL;
    1364                 :             :   GData *d;
    1365                 :             :   GDataElt *data;
    1366                 :      229345 :   GData *d_to_free = NULL;
    1367                 :      229345 :   gboolean set_d = FALSE;
    1368                 :             :   guint32 idx;
    1369                 :             : 
    1370                 :      229345 :   g_return_val_if_fail (datalist != NULL, FALSE);
    1371                 :      229345 :   g_return_val_if_fail (key_id != 0, FALSE);
    1372                 :             : 
    1373                 :      229345 :   if (old_destroy)
    1374                 :           5 :     *old_destroy = NULL;
    1375                 :             : 
    1376                 :      229345 :   d = g_datalist_lock_and_get (datalist);
    1377                 :             : 
    1378                 :      229345 :   data = datalist_find (d, key_id, &idx);
    1379                 :      229345 :   if (data)
    1380                 :             :     {
    1381                 :      229343 :       val = data->data;
    1382                 :      229343 :       if (val == oldval)
    1383                 :             :         {
    1384                 :      100002 :           if (old_destroy)
    1385                 :           2 :             *old_destroy = data->destroy;
    1386                 :      100002 :           if (newval != NULL)
    1387                 :             :             {
    1388                 :      100001 :               data->data = newval;
    1389                 :      100001 :               data->destroy = destroy;
    1390                 :             :             }
    1391                 :             :           else
    1392                 :             :             {
    1393                 :           1 :               datalist_remove (d, idx);
    1394                 :           1 :               if (datalist_shrink (&d, &d_to_free))
    1395                 :           1 :                 set_d = TRUE;
    1396                 :             :             }
    1397                 :             :         }
    1398                 :             :     }
    1399                 :             :   else
    1400                 :             :     {
    1401                 :           2 :       if (oldval == NULL && newval != NULL)
    1402                 :             :         {
    1403                 :           2 :           if (datalist_append (&d, key_id, newval, destroy))
    1404                 :           2 :             set_d = TRUE;
    1405                 :             :         }
    1406                 :             :     }
    1407                 :             : 
    1408                 :      229345 :   if (set_d)
    1409                 :           3 :     g_datalist_unlock_and_set (datalist, d);
    1410                 :             :   else
    1411                 :      229342 :     g_datalist_unlock (datalist);
    1412                 :             : 
    1413                 :      229345 :   if (G_UNLIKELY (d_to_free))
    1414                 :           1 :     g_free (d_to_free);
    1415                 :             : 
    1416                 :      229345 :   return val == oldval;
    1417                 :             : }
    1418                 :             : 
    1419                 :             : /**
    1420                 :             :  * g_datalist_get_data:
    1421                 :             :  * @datalist: a datalist.
    1422                 :             :  * @key: the string identifying a data element.
    1423                 :             :  *
    1424                 :             :  * Gets a data element, using its string identifier. This is slower than
    1425                 :             :  * g_datalist_id_get_data() because it compares strings.
    1426                 :             :  *
    1427                 :             :  * Returns: (transfer none) (nullable): the data element, or %NULL if it
    1428                 :             :  *          is not found.
    1429                 :             :  **/
    1430                 :             : gpointer
    1431                 :      288422 : g_datalist_get_data (GData **datalist,
    1432                 :             :                      const gchar *key)
    1433                 :             : {
    1434                 :             :   GQuark key_id;
    1435                 :             :   GHashTable *index;
    1436                 :      288422 :   gpointer res = NULL;
    1437                 :             :   GDataElt *data_elt;
    1438                 :             :   GData *d;
    1439                 :             : 
    1440                 :      288422 :   g_return_val_if_fail (datalist != NULL, NULL);
    1441                 :             : 
    1442                 :      288422 :   if (G_UNLIKELY (!key))
    1443                 :           4 :     return NULL;
    1444                 :             : 
    1445                 :      288418 :   d = g_datalist_lock_and_get (datalist);
    1446                 :             : 
    1447                 :      288418 :   if (!d)
    1448                 :         360 :     goto out;
    1449                 :             : 
    1450                 :      288058 :   index = datalist_index_get (d);
    1451                 :             : 
    1452                 :      288058 :   if (G_LIKELY (!index))
    1453                 :             :     {
    1454                 :             :       guint32 i;
    1455                 :             : 
    1456                 :      289591 :       for (i = 0; i < d->len; i++)
    1457                 :             :         {
    1458                 :             :           const char *qstr;
    1459                 :             : 
    1460                 :      288588 :           data_elt = &d->data[i];
    1461                 :             :           /* Here we intentionally compare by strings, instead of calling
    1462                 :             :            * g_quark_try_string() first.
    1463                 :             :            *
    1464                 :             :            * See commit 1cceda49b60b ('Make g_datalist_get_data not look up the
    1465                 :             :            * quark').
    1466                 :             :            */
    1467                 :      288588 :           qstr = g_quark_to_string (data_elt->key);
    1468                 :      288588 :           if (qstr && strcmp (qstr, key) == 0)
    1469                 :             :             {
    1470                 :      285580 :               res = data_elt->data;
    1471                 :      285580 :               goto out;
    1472                 :             :             }
    1473                 :             :         }
    1474                 :        1003 :       goto out;
    1475                 :             :     }
    1476                 :             : 
    1477                 :        1475 :   key_id = g_quark_try_string (key);
    1478                 :        1475 :   if (key_id == 0)
    1479                 :           0 :     goto out;
    1480                 :             : 
    1481                 :        1475 :   data_elt = g_hash_table_lookup (index, &key_id);
    1482                 :             : 
    1483                 :        1475 :   if (data_elt)
    1484                 :        1474 :     res = data_elt->data;
    1485                 :             : 
    1486                 :           1 : out:
    1487                 :      288418 :   g_datalist_unlock (datalist);
    1488                 :             : 
    1489                 :      288418 :   return res;
    1490                 :             : }
    1491                 :             : 
    1492                 :             : /**
    1493                 :             :  * GDataForeachFunc:
    1494                 :             :  * @key_id: the #GQuark id to identifying the data element.
    1495                 :             :  * @data: the data element.
    1496                 :             :  * @user_data: (closure): user data passed to g_dataset_foreach().
    1497                 :             :  *
    1498                 :             :  * Specifies the type of function passed to g_dataset_foreach(). It is
    1499                 :             :  * called with each #GQuark id and associated data element, together
    1500                 :             :  * with the @user_data parameter supplied to g_dataset_foreach().
    1501                 :             :  **/
    1502                 :             : 
    1503                 :             : /**
    1504                 :             :  * g_dataset_foreach:
    1505                 :             :  * @dataset_location: (not nullable): the location identifying the dataset.
    1506                 :             :  * @func: (scope call) (closure user_data): the function to call for each data element.
    1507                 :             :  * @user_data: user data to pass to the function.
    1508                 :             :  *
    1509                 :             :  * Calls the given function for each data element which is associated
    1510                 :             :  * with the given location. Note that this function is NOT thread-safe.
    1511                 :             :  * So unless @dataset_location can be protected from any modifications
    1512                 :             :  * during invocation of this function, it should not be called.
    1513                 :             :  *
    1514                 :             :  * @func can make changes to the dataset, but the iteration will not
    1515                 :             :  * reflect changes made during the g_dataset_foreach() call, other
    1516                 :             :  * than skipping over elements that are removed.
    1517                 :             :  **/
    1518                 :             : void
    1519                 :           1 : g_dataset_foreach (gconstpointer    dataset_location,
    1520                 :             :                    GDataForeachFunc func,
    1521                 :             :                    gpointer         user_data)
    1522                 :             : {
    1523                 :             :   GDataset *dataset;
    1524                 :             :   
    1525                 :           1 :   g_return_if_fail (dataset_location != NULL);
    1526                 :           1 :   g_return_if_fail (func != NULL);
    1527                 :             : 
    1528                 :           1 :   G_LOCK (g_dataset_global);
    1529                 :           1 :   if (g_dataset_location_ht)
    1530                 :             :     {
    1531                 :           1 :       dataset = g_dataset_lookup (dataset_location);
    1532                 :           1 :       G_UNLOCK (g_dataset_global);
    1533                 :           1 :       if (dataset)
    1534                 :           1 :         g_datalist_foreach (&dataset->datalist, func, user_data);
    1535                 :             :     }
    1536                 :             :   else
    1537                 :             :     {
    1538                 :           0 :       G_UNLOCK (g_dataset_global);
    1539                 :             :     }
    1540                 :             : }
    1541                 :             : 
    1542                 :             : /**
    1543                 :             :  * g_datalist_foreach:
    1544                 :             :  * @datalist: a datalist.
    1545                 :             :  * @func: (scope call) (closure user_data): the function to call for each data element.
    1546                 :             :  * @user_data: user data to pass to the function.
    1547                 :             :  *
    1548                 :             :  * Calls the given function for each data element of the datalist. The
    1549                 :             :  * function is called with each data element's #GQuark id and data,
    1550                 :             :  * together with the given @user_data parameter. Note that this
    1551                 :             :  * function is NOT thread-safe. So unless @datalist can be protected
    1552                 :             :  * from any modifications during invocation of this function, it should
    1553                 :             :  * not be called.
    1554                 :             :  *
    1555                 :             :  * @func can make changes to @datalist, but the iteration will not
    1556                 :             :  * reflect changes made during the g_datalist_foreach() call, other
    1557                 :             :  * than skipping over elements that are removed.
    1558                 :             :  **/
    1559                 :             : void
    1560                 :           3 : g_datalist_foreach (GData          **datalist,
    1561                 :             :                     GDataForeachFunc func,
    1562                 :             :                     gpointer         user_data)
    1563                 :             : {
    1564                 :             :   GData *d;
    1565                 :             :   guint i, j, len;
    1566                 :             :   GQuark *keys;
    1567                 :             : 
    1568                 :           3 :   g_return_if_fail (datalist != NULL);
    1569                 :           3 :   g_return_if_fail (func != NULL);
    1570                 :             : 
    1571                 :           3 :   d = G_DATALIST_GET_POINTER (datalist);
    1572                 :           3 :   if (d == NULL) 
    1573                 :           1 :     return;
    1574                 :             : 
    1575                 :             :   /* We make a copy of the keys so that we can handle it changing
    1576                 :             :      in the callback */
    1577                 :           2 :   len = d->len;
    1578                 :           2 :   keys = g_new (GQuark, len);
    1579                 :           8 :   for (i = 0; i < len; i++)
    1580                 :           6 :     keys[i] = d->data[i].key;
    1581                 :             :   
    1582                 :           8 :   for (i = 0; i < len; i++)
    1583                 :             :     {
    1584                 :             :       /* A previous callback might have removed a later item, so always check that
    1585                 :             :          it still exists before calling */
    1586                 :           6 :       d = G_DATALIST_GET_POINTER (datalist);
    1587                 :             :       
    1588                 :           6 :       if (d == NULL)
    1589                 :           0 :         break;
    1590                 :          12 :       for (j = 0; j < d->len; j++)
    1591                 :             :         {
    1592                 :          12 :           if (d->data[j].key == keys[i]) {
    1593                 :           6 :             func (d->data[i].key, d->data[i].data, user_data);
    1594                 :           6 :             break;
    1595                 :             :           }
    1596                 :             :         }
    1597                 :             :     }
    1598                 :           2 :   g_free (keys);
    1599                 :             : }
    1600                 :             : 
    1601                 :             : /**
    1602                 :             :  * g_datalist_init: (skip)
    1603                 :             :  * @datalist: a pointer to a pointer to a datalist.
    1604                 :             :  *
    1605                 :             :  * Resets the datalist to %NULL. It does not free any memory or call
    1606                 :             :  * any destroy functions.
    1607                 :             :  **/
    1608                 :             : void
    1609                 :          29 : g_datalist_init (GData **datalist)
    1610                 :             : {
    1611                 :          29 :   g_return_if_fail (datalist != NULL);
    1612                 :             : 
    1613                 :          29 :   g_atomic_pointer_set (datalist, NULL);
    1614                 :             : }
    1615                 :             : 
    1616                 :             : /**
    1617                 :             :  * g_datalist_set_flags:
    1618                 :             :  * @datalist: pointer to the location that holds a list
    1619                 :             :  * @flags: the flags to turn on. The values of the flags are
    1620                 :             :  *   restricted by %G_DATALIST_FLAGS_MASK (currently
    1621                 :             :  *   3; giving two possible boolean flags).
    1622                 :             :  *   A value for @flags that doesn't fit within the mask is
    1623                 :             :  *   an error.
    1624                 :             :  * 
    1625                 :             :  * Turns on flag values for a data list. This function is used
    1626                 :             :  * to keep a small number of boolean flags in an object with
    1627                 :             :  * a data list without using any additional space. It is
    1628                 :             :  * not generally useful except in circumstances where space
    1629                 :             :  * is very tight. (It is used in the base #GObject type, for
    1630                 :             :  * example.)
    1631                 :             :  *
    1632                 :             :  * Since: 2.8
    1633                 :             :  **/
    1634                 :             : void
    1635                 :      111424 : g_datalist_set_flags (GData **datalist,
    1636                 :             :                       guint   flags)
    1637                 :             : {
    1638                 :      111424 :   g_return_if_fail (datalist != NULL);
    1639                 :      111424 :   g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
    1640                 :             : 
    1641                 :      111424 :   g_atomic_pointer_or (datalist, (gsize)flags);
    1642                 :             : }
    1643                 :             : 
    1644                 :             : /**
    1645                 :             :  * g_datalist_unset_flags:
    1646                 :             :  * @datalist: pointer to the location that holds a list
    1647                 :             :  * @flags: the flags to turn off. The values of the flags are
    1648                 :             :  *   restricted by %G_DATALIST_FLAGS_MASK (currently
    1649                 :             :  *   3: giving two possible boolean flags).
    1650                 :             :  *   A value for @flags that doesn't fit within the mask is
    1651                 :             :  *   an error.
    1652                 :             :  * 
    1653                 :             :  * Turns off flag values for a data list. See g_datalist_unset_flags()
    1654                 :             :  *
    1655                 :             :  * Since: 2.8
    1656                 :             :  **/
    1657                 :             : void
    1658                 :      100015 : g_datalist_unset_flags (GData **datalist,
    1659                 :             :                         guint   flags)
    1660                 :             : {
    1661                 :      100015 :   g_return_if_fail (datalist != NULL);
    1662                 :      100015 :   g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
    1663                 :             : 
    1664                 :      100015 :   g_atomic_pointer_and (datalist, ~(gsize)flags);
    1665                 :             : }
    1666                 :             : 
    1667                 :             : /**
    1668                 :             :  * g_datalist_get_flags:
    1669                 :             :  * @datalist: pointer to the location that holds a list
    1670                 :             :  * 
    1671                 :             :  * Gets flags values packed in together with the datalist.
    1672                 :             :  * See g_datalist_set_flags().
    1673                 :             :  * 
    1674                 :             :  * Returns: the flags of the datalist
    1675                 :             :  *
    1676                 :             :  * Since: 2.8
    1677                 :             :  **/
    1678                 :             : guint
    1679                 :   229454738 : g_datalist_get_flags (GData **datalist)
    1680                 :             : {
    1681                 :   229454738 :   g_return_val_if_fail (datalist != NULL, 0);
    1682                 :             :   
    1683                 :   229454738 :   return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
    1684                 :             : }
    1685                 :             : 
    1686                 :             : /* HOLDS: g_dataset_global_lock */
    1687                 :             : static void
    1688                 :           1 : g_data_initialize (void)
    1689                 :             : {
    1690                 :           1 :   g_return_if_fail (g_dataset_location_ht == NULL);
    1691                 :             : 
    1692                 :           1 :   g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
    1693                 :           1 :   g_dataset_cached = NULL;
    1694                 :             : }
        

Generated by: LCOV version 2.0-1