• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /*
22  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GLib Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GLib at ftp://ftp.gtk.org/pub/gtk/.
26  */
27 
28 /*
29  * MT safe ; except for g_data*_foreach()
30  */
31 
32 #include "config.h"
33 
34 #include <string.h>
35 
36 #include "gdataset.h"
37 #include "gbitlock.h"
38 
39 #include "gslice.h"
40 #include "gdatasetprivate.h"
41 #include "ghash.h"
42 #include "gquark.h"
43 #include "gstrfuncs.h"
44 #include "gtestutils.h"
45 #include "gthread.h"
46 #include "glib_trace.h"
47 
48 /**
49  * SECTION:datasets
50  * @title: Datasets
51  * @short_description: associate groups of data elements with
52  *                     particular memory locations
53  *
54  * Datasets associate groups of data elements with particular memory
55  * locations. These are useful if you need to associate data with a
56  * structure returned from an external library. Since you cannot modify
57  * the structure, you use its location in memory as the key into a
58  * dataset, where you can associate any number of data elements with it.
59  *
60  * There are two forms of most of the dataset functions. The first form
61  * uses strings to identify the data elements associated with a
62  * location. The second form uses #GQuark identifiers, which are
63  * created with a call to g_quark_from_string() or
64  * g_quark_from_static_string(). The second form is quicker, since it
65  * does not require looking up the string in the hash table of #GQuark
66  * identifiers.
67  *
68  * There is no function to create a dataset. It is automatically
69  * created as soon as you add elements to it.
70  *
71  * To add data elements to a dataset use g_dataset_id_set_data(),
72  * g_dataset_id_set_data_full(), g_dataset_set_data() and
73  * g_dataset_set_data_full().
74  *
75  * To get data elements from a dataset use g_dataset_id_get_data() and
76  * g_dataset_get_data().
77  *
78  * To iterate over all data elements in a dataset use
79  * g_dataset_foreach() (not thread-safe).
80  *
81  * To remove data elements from a dataset use
82  * g_dataset_id_remove_data() and g_dataset_remove_data().
83  *
84  * To destroy a dataset, use g_dataset_destroy().
85  **/
86 
87 /**
88  * SECTION:datalist
89  * @title: Keyed Data Lists
90  * @short_description: lists of data elements which are accessible by a
91  *                     string or GQuark identifier
92  *
93  * Keyed data lists provide lists of arbitrary data elements which can
94  * be accessed either with a string or with a #GQuark corresponding to
95  * the string.
96  *
97  * The #GQuark methods are quicker, since the strings have to be
98  * converted to #GQuarks anyway.
99  *
100  * Data lists are used for associating arbitrary data with #GObjects,
101  * using g_object_set_data() and related functions.
102  *
103  * To create a datalist, use g_datalist_init().
104  *
105  * To add data elements to a datalist use g_datalist_id_set_data(),
106  * g_datalist_id_set_data_full(), g_datalist_set_data() and
107  * g_datalist_set_data_full().
108  *
109  * To get data elements from a datalist use g_datalist_id_get_data()
110  * and g_datalist_get_data().
111  *
112  * To iterate over all data elements in a datalist use
113  * g_datalist_foreach() (not thread-safe).
114  *
115  * To remove data elements from a datalist use
116  * g_datalist_id_remove_data() and g_datalist_remove_data().
117  *
118  * To remove all data elements from a datalist, use g_datalist_clear().
119  **/
120 
121 /**
122  * GData:
123  *
124  * The #GData struct is an opaque data structure to represent a
125  * [Keyed Data List][glib-Keyed-Data-Lists]. It should only be
126  * accessed via the following functions.
127  **/
128 
129 /**
130  * GDestroyNotify:
131  * @data: the data element.
132  *
133  * Specifies the type of function which is called when a data element
134  * is destroyed. It is passed the pointer to the data element and
135  * should free any memory and resources allocated for it.
136  **/
137 
138 #define G_DATALIST_FLAGS_MASK_INTERNAL 0x7
139 
140 /* datalist pointer accesses have to be carried out atomically */
141 #define G_DATALIST_GET_POINTER(datalist)						\
142   ((GData*) ((gsize) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK_INTERNAL))
143 
144 #define G_DATALIST_SET_POINTER(datalist, pointer)       G_STMT_START {                  \
145   gpointer _oldv, _newv;                                                                \
146   do {                                                                                  \
147     _oldv = g_atomic_pointer_get (datalist);                                            \
148     _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK_INTERNAL) | (gsize) pointer);     \
149   } while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, _oldv, _newv));   \
150 } G_STMT_END
151 
152 /* --- structures --- */
153 typedef struct {
154   GQuark          key;
155   gpointer        data;
156   GDestroyNotify  destroy;
157 } GDataElt;
158 
159 typedef struct _GDataset GDataset;
160 struct _GData
161 {
162   guint32  len;     /* Number of elements */
163   guint32  alloc;   /* Number of allocated elements */
164   GDataElt data[1]; /* Flexible array */
165 };
166 
167 struct _GDataset
168 {
169   gconstpointer location;
170   GData        *datalist;
171 };
172 
173 
174 /* --- prototypes --- */
175 static inline GDataset*	g_dataset_lookup		(gconstpointer	  dataset_location);
176 static inline void	g_datalist_clear_i		(GData		**datalist);
177 static void		g_dataset_destroy_internal	(GDataset	 *dataset);
178 static inline gpointer	g_data_set_internal		(GData     	**datalist,
179 							 GQuark   	  key_id,
180 							 gpointer         data,
181 							 GDestroyNotify   destroy_func,
182 							 GDataset	 *dataset);
183 static void		g_data_initialize		(void);
184 
185 /* Locking model:
186  * Each standalone GDataList is protected by a bitlock in the datalist pointer,
187  * which protects that modification of the non-flags part of the datalist pointer
188  * and the contents of the datalist.
189  *
190  * For GDataSet we have a global lock g_dataset_global that protects
191  * the global dataset hash and cache, and additionally it protects the
192  * datalist such that we can avoid to use the bit lock in a few places
193  * where it is easy.
194  */
195 
196 /* --- variables --- */
197 G_LOCK_DEFINE_STATIC (g_dataset_global);
198 static GHashTable   *g_dataset_location_ht = NULL;
199 static GDataset     *g_dataset_cached = NULL; /* should this be
200 						 thread specific? */
201 
202 /* --- functions --- */
203 
204 #define DATALIST_LOCK_BIT 2
205 
206 static void
g_datalist_lock(GData ** datalist)207 g_datalist_lock (GData **datalist)
208 {
209   g_pointer_bit_lock ((void **)datalist, DATALIST_LOCK_BIT);
210 }
211 
212 static void
g_datalist_unlock(GData ** datalist)213 g_datalist_unlock (GData **datalist)
214 {
215   g_pointer_bit_unlock ((void **)datalist, DATALIST_LOCK_BIT);
216 }
217 
218 /* Called with the datalist lock held, or the dataset global
219  * lock for dataset lists
220  */
221 static void
g_datalist_clear_i(GData ** datalist)222 g_datalist_clear_i (GData **datalist)
223 {
224   GData *data;
225   guint i;
226 
227   data = G_DATALIST_GET_POINTER (datalist);
228   G_DATALIST_SET_POINTER (datalist, NULL);
229 
230   if (data)
231     {
232       G_UNLOCK (g_dataset_global);
233       for (i = 0; i < data->len; i++)
234         {
235           if (data->data[i].data && data->data[i].destroy)
236             data->data[i].destroy (data->data[i].data);
237         }
238       G_LOCK (g_dataset_global);
239 
240       g_free (data);
241     }
242 
243 }
244 
245 /**
246  * g_datalist_clear: (skip)
247  * @datalist: a datalist.
248  *
249  * Frees all the data elements of the datalist.
250  * The data elements' destroy functions are called
251  * if they have been set.
252  **/
253 void
g_datalist_clear(GData ** datalist)254 g_datalist_clear (GData **datalist)
255 {
256   GData *data;
257   guint i;
258 
259   g_return_if_fail (datalist != NULL);
260 
261   g_datalist_lock (datalist);
262 
263   data = G_DATALIST_GET_POINTER (datalist);
264   G_DATALIST_SET_POINTER (datalist, NULL);
265 
266   g_datalist_unlock (datalist);
267 
268   if (data)
269     {
270       for (i = 0; i < data->len; i++)
271         {
272           if (data->data[i].data && data->data[i].destroy)
273             data->data[i].destroy (data->data[i].data);
274         }
275 
276       g_free (data);
277     }
278 }
279 
280 /* HOLDS: g_dataset_global_lock */
281 static inline GDataset*
g_dataset_lookup(gconstpointer dataset_location)282 g_dataset_lookup (gconstpointer	dataset_location)
283 {
284   GDataset *dataset;
285 
286   if (g_dataset_cached && g_dataset_cached->location == dataset_location)
287     return g_dataset_cached;
288 
289   dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
290   if (dataset)
291     g_dataset_cached = dataset;
292 
293   return dataset;
294 }
295 
296 /* HOLDS: g_dataset_global_lock */
297 static void
g_dataset_destroy_internal(GDataset * dataset)298 g_dataset_destroy_internal (GDataset *dataset)
299 {
300   gconstpointer dataset_location;
301 
302   dataset_location = dataset->location;
303   while (dataset)
304     {
305       if (G_DATALIST_GET_POINTER(&dataset->datalist) == NULL)
306 	{
307 	  if (dataset == g_dataset_cached)
308 	    g_dataset_cached = NULL;
309 	  g_hash_table_remove (g_dataset_location_ht, dataset_location);
310 	  g_slice_free (GDataset, dataset);
311 	  break;
312 	}
313 
314       g_datalist_clear_i (&dataset->datalist);
315       dataset = g_dataset_lookup (dataset_location);
316     }
317 }
318 
319 /**
320  * g_dataset_destroy:
321  * @dataset_location: (not nullable): the location identifying the dataset.
322  *
323  * Destroys the dataset, freeing all memory allocated, and calling any
324  * destroy functions set for data elements.
325  */
326 void
g_dataset_destroy(gconstpointer dataset_location)327 g_dataset_destroy (gconstpointer  dataset_location)
328 {
329   g_return_if_fail (dataset_location != NULL);
330 
331   G_LOCK (g_dataset_global);
332   if (g_dataset_location_ht)
333     {
334       GDataset *dataset;
335 
336       dataset = g_dataset_lookup (dataset_location);
337       if (dataset)
338 	g_dataset_destroy_internal (dataset);
339     }
340   G_UNLOCK (g_dataset_global);
341 }
342 
343 /* HOLDS: g_dataset_global_lock if dataset != null */
344 static inline gpointer
g_data_set_internal(GData ** datalist,GQuark key_id,gpointer new_data,GDestroyNotify new_destroy_func,GDataset * dataset)345 g_data_set_internal (GData	  **datalist,
346 		     GQuark         key_id,
347 		     gpointer       new_data,
348 		     GDestroyNotify new_destroy_func,
349 		     GDataset	   *dataset)
350 {
351   GData *d, *old_d;
352   GDataElt old, *data, *data_last, *data_end;
353 
354   g_datalist_lock (datalist);
355 
356   d = G_DATALIST_GET_POINTER (datalist);
357 
358   if (new_data == NULL) /* remove */
359     {
360       if (d)
361 	{
362 	  data = d->data;
363 	  data_last = data + d->len - 1;
364 	  while (data <= data_last)
365 	    {
366 	      if (data->key == key_id)
367 		{
368 		  old = *data;
369 		  if (data != data_last)
370 		    *data = *data_last;
371 		  d->len--;
372 
373 		  /* We don't bother to shrink, but if all data are now gone
374 		   * we at least free the memory
375                    */
376 		  if (d->len == 0)
377 		    {
378 		      G_DATALIST_SET_POINTER (datalist, NULL);
379 		      g_free (d);
380 		      /* datalist may be situated in dataset, so must not be
381 		       * unlocked after we free it
382 		       */
383 		      g_datalist_unlock (datalist);
384 
385 		      /* the dataset destruction *must* be done
386 		       * prior to invocation of the data destroy function
387 		       */
388 		      if (dataset)
389 			g_dataset_destroy_internal (dataset);
390 		    }
391 		  else
392 		    {
393 		      g_datalist_unlock (datalist);
394 		    }
395 
396 		  /* We found and removed an old value
397 		   * the GData struct *must* already be unlinked
398 		   * when invoking the destroy function.
399 		   * we use (new_data==NULL && new_destroy_func!=NULL) as
400 		   * a special hint combination to "steal"
401 		   * data without destroy notification
402 		   */
403 		  if (old.destroy && !new_destroy_func)
404 		    {
405 		      if (dataset)
406 			G_UNLOCK (g_dataset_global);
407 		      old.destroy (old.data);
408 		      if (dataset)
409 			G_LOCK (g_dataset_global);
410 		      old.data = NULL;
411 		    }
412 
413 		  return old.data;
414 		}
415 	      data++;
416 	    }
417 	}
418     }
419   else
420     {
421       old.data = NULL;
422       if (d)
423 	{
424 	  data = d->data;
425 	  data_end = data + d->len;
426 	  while (data < data_end)
427 	    {
428 	      if (data->key == key_id)
429 		{
430 		  if (!data->destroy)
431 		    {
432 		      data->data = new_data;
433 		      data->destroy = new_destroy_func;
434 		      g_datalist_unlock (datalist);
435 		    }
436 		  else
437 		    {
438 		      old = *data;
439 		      data->data = new_data;
440 		      data->destroy = new_destroy_func;
441 
442 		      g_datalist_unlock (datalist);
443 
444 		      /* We found and replaced an old value
445 		       * the GData struct *must* already be unlinked
446 		       * when invoking the destroy function.
447 		       */
448 		      if (dataset)
449 			G_UNLOCK (g_dataset_global);
450 		      old.destroy (old.data);
451 		      if (dataset)
452 			G_LOCK (g_dataset_global);
453 		    }
454 		  return NULL;
455 		}
456 	      data++;
457 	    }
458 	}
459 
460       /* The key was not found, insert it */
461       old_d = d;
462       if (d == NULL)
463 	{
464 	  d = g_malloc (sizeof (GData));
465 	  d->len = 0;
466 	  d->alloc = 1;
467 	}
468       else if (d->len == d->alloc)
469 	{
470 	  d->alloc = d->alloc * 2;
471 	  d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt));
472 	}
473       if (old_d != d)
474 	G_DATALIST_SET_POINTER (datalist, d);
475 
476       d->data[d->len].key = key_id;
477       d->data[d->len].data = new_data;
478       d->data[d->len].destroy = new_destroy_func;
479       d->len++;
480     }
481 
482   g_datalist_unlock (datalist);
483 
484   return NULL;
485 
486 }
487 
488 /**
489  * g_dataset_id_set_data_full: (skip)
490  * @dataset_location: (not nullable): the location identifying the dataset.
491  * @key_id: the #GQuark id to identify the data element.
492  * @data: the data element.
493  * @destroy_func: the function to call when the data element is
494  *                removed. This function will be called with the data
495  *                element and can be used to free any memory allocated
496  *                for it.
497  *
498  * Sets the data element associated with the given #GQuark id, and also
499  * the function to call when the data element is destroyed. Any
500  * previous data with the same key is removed, and its destroy function
501  * is called.
502  **/
503 /**
504  * g_dataset_set_data_full: (skip)
505  * @l: the location identifying the dataset.
506  * @k: the string to identify the data element.
507  * @d: the data element.
508  * @f: the function to call when the data element is removed. This
509  *     function will be called with the data element and can be used to
510  *     free any memory allocated for it.
511  *
512  * Sets the data corresponding to the given string identifier, and the
513  * function to call when the data element is destroyed.
514  **/
515 /**
516  * g_dataset_id_set_data:
517  * @l: the location identifying the dataset.
518  * @k: the #GQuark id to identify the data element.
519  * @d: the data element.
520  *
521  * Sets the data element associated with the given #GQuark id. Any
522  * previous data with the same key is removed, and its destroy function
523  * is called.
524  **/
525 /**
526  * g_dataset_set_data:
527  * @l: the location identifying the dataset.
528  * @k: the string to identify the data element.
529  * @d: the data element.
530  *
531  * Sets the data corresponding to the given string identifier.
532  **/
533 /**
534  * g_dataset_id_remove_data:
535  * @l: the location identifying the dataset.
536  * @k: the #GQuark id identifying the data element.
537  *
538  * Removes a data element from a dataset. The data element's destroy
539  * function is called if it has been set.
540  **/
541 /**
542  * g_dataset_remove_data:
543  * @l: the location identifying the dataset.
544  * @k: the string identifying the data element.
545  *
546  * Removes a data element corresponding to a string. Its destroy
547  * function is called if it has been set.
548  **/
549 void
g_dataset_id_set_data_full(gconstpointer dataset_location,GQuark key_id,gpointer data,GDestroyNotify destroy_func)550 g_dataset_id_set_data_full (gconstpointer  dataset_location,
551 			    GQuark         key_id,
552 			    gpointer       data,
553 			    GDestroyNotify destroy_func)
554 {
555   GDataset *dataset;
556 
557   g_return_if_fail (dataset_location != NULL);
558   if (!data)
559     g_return_if_fail (destroy_func == NULL);
560   if (!key_id)
561     {
562       if (data)
563 	g_return_if_fail (key_id > 0);
564       else
565 	return;
566     }
567 
568   G_LOCK (g_dataset_global);
569   if (!g_dataset_location_ht)
570     g_data_initialize ();
571 
572   dataset = g_dataset_lookup (dataset_location);
573   if (!dataset)
574     {
575       dataset = g_slice_new (GDataset);
576       dataset->location = dataset_location;
577       g_datalist_init (&dataset->datalist);
578       g_hash_table_insert (g_dataset_location_ht,
579 			   (gpointer) dataset->location,
580 			   dataset);
581     }
582 
583   g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
584   G_UNLOCK (g_dataset_global);
585 }
586 
587 /**
588  * g_datalist_id_set_data_full: (skip)
589  * @datalist: a datalist.
590  * @key_id: the #GQuark to identify the data element.
591  * @data: (nullable): the data element or %NULL to remove any previous element
592  *        corresponding to @key_id.
593  * @destroy_func: (nullable): the function to call when the data element is
594  *                removed. This function will be called with the data
595  *                element and can be used to free any memory allocated
596  *                for it. If @data is %NULL, then @destroy_func must
597  *                also be %NULL.
598  *
599  * Sets the data corresponding to the given #GQuark id, and the
600  * function to be called when the element is removed from the datalist.
601  * Any previous data with the same key is removed, and its destroy
602  * function is called.
603  **/
604 /**
605  * g_datalist_set_data_full: (skip)
606  * @dl: a datalist.
607  * @k: the string to identify the data element.
608  * @d: (nullable): the data element, or %NULL to remove any previous element
609  *     corresponding to @k.
610  * @f: (nullable): the function to call when the data element is removed.
611  *     This function will be called with the data element and can be used to
612  *     free any memory allocated for it. If @d is %NULL, then @f must
613  *     also be %NULL.
614  *
615  * Sets the data element corresponding to the given string identifier,
616  * and the function to be called when the data element is removed.
617  **/
618 /**
619  * g_datalist_id_set_data:
620  * @dl: a datalist.
621  * @q: the #GQuark to identify the data element.
622  * @d: (nullable): the data element, or %NULL to remove any previous element
623  *     corresponding to @q.
624  *
625  * Sets the data corresponding to the given #GQuark id. Any previous
626  * data with the same key is removed, and its destroy function is
627  * called.
628  **/
629 /**
630  * g_datalist_set_data:
631  * @dl: a datalist.
632  * @k: the string to identify the data element.
633  * @d: (nullable): the data element, or %NULL to remove any previous element
634  *     corresponding to @k.
635  *
636  * Sets the data element corresponding to the given string identifier.
637  **/
638 /**
639  * g_datalist_id_remove_data:
640  * @dl: a datalist.
641  * @q: the #GQuark identifying the data element.
642  *
643  * Removes an element, using its #GQuark identifier.
644  **/
645 /**
646  * g_datalist_remove_data:
647  * @dl: a datalist.
648  * @k: the string identifying the data element.
649  *
650  * Removes an element using its string identifier. The data element's
651  * destroy function is called if it has been set.
652  **/
653 void
g_datalist_id_set_data_full(GData ** datalist,GQuark key_id,gpointer data,GDestroyNotify destroy_func)654 g_datalist_id_set_data_full (GData	  **datalist,
655 			     GQuark         key_id,
656 			     gpointer       data,
657 			     GDestroyNotify destroy_func)
658 {
659   g_return_if_fail (datalist != NULL);
660   if (!data)
661     g_return_if_fail (destroy_func == NULL);
662   if (!key_id)
663     {
664       if (data)
665 	g_return_if_fail (key_id > 0);
666       else
667 	return;
668     }
669 
670   g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
671 }
672 
673 /**
674  * g_dataset_id_remove_no_notify: (skip)
675  * @dataset_location: (not nullable): the location identifying the dataset.
676  * @key_id: the #GQuark ID identifying the data element.
677  *
678  * Removes an element, without calling its destroy notification
679  * function.
680  *
681  * Returns: (nullable): the data previously stored at @key_id,
682  *          or %NULL if none.
683  **/
684 /**
685  * g_dataset_remove_no_notify: (skip)
686  * @l: the location identifying the dataset.
687  * @k: the string identifying the data element.
688  *
689  * Removes an element, without calling its destroy notifier.
690  **/
691 gpointer
g_dataset_id_remove_no_notify(gconstpointer dataset_location,GQuark key_id)692 g_dataset_id_remove_no_notify (gconstpointer  dataset_location,
693 			       GQuark         key_id)
694 {
695   gpointer ret_data = NULL;
696 
697   g_return_val_if_fail (dataset_location != NULL, NULL);
698 
699   G_LOCK (g_dataset_global);
700   if (key_id && g_dataset_location_ht)
701     {
702       GDataset *dataset;
703 
704       dataset = g_dataset_lookup (dataset_location);
705       if (dataset)
706 	ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
707     }
708   G_UNLOCK (g_dataset_global);
709 
710   return ret_data;
711 }
712 
713 /**
714  * g_datalist_id_remove_no_notify: (skip)
715  * @datalist: a datalist.
716  * @key_id: the #GQuark identifying a data element.
717  *
718  * Removes an element, without calling its destroy notification
719  * function.
720  *
721  * Returns: (nullable): the data previously stored at @key_id,
722  *          or %NULL if none.
723  **/
724 /**
725  * g_datalist_remove_no_notify: (skip)
726  * @dl: a datalist.
727  * @k: the string identifying the data element.
728  *
729  * Removes an element, without calling its destroy notifier.
730  **/
731 gpointer
g_datalist_id_remove_no_notify(GData ** datalist,GQuark key_id)732 g_datalist_id_remove_no_notify (GData	**datalist,
733 				GQuark    key_id)
734 {
735   gpointer ret_data = NULL;
736 
737   g_return_val_if_fail (datalist != NULL, NULL);
738 
739   if (key_id)
740     ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
741 
742   return ret_data;
743 }
744 
745 /**
746  * g_dataset_id_get_data:
747  * @dataset_location: (not nullable): the location identifying the dataset.
748  * @key_id: the #GQuark id to identify the data element.
749  *
750  * Gets the data element corresponding to a #GQuark.
751  *
752  * Returns: (transfer none) (nullable): the data element corresponding to
753  *          the #GQuark, or %NULL if it is not found.
754  **/
755 /**
756  * g_dataset_get_data:
757  * @l: the location identifying the dataset.
758  * @k: the string identifying the data element.
759  *
760  * Gets the data element corresponding to a string.
761  *
762  * Returns: (transfer none) (nullable): the data element corresponding to
763  *          the string, or %NULL if it is not found.
764  **/
765 gpointer
g_dataset_id_get_data(gconstpointer dataset_location,GQuark key_id)766 g_dataset_id_get_data (gconstpointer  dataset_location,
767 		       GQuark         key_id)
768 {
769   gpointer retval = NULL;
770 
771   g_return_val_if_fail (dataset_location != NULL, NULL);
772 
773   G_LOCK (g_dataset_global);
774   if (key_id && g_dataset_location_ht)
775     {
776       GDataset *dataset;
777 
778       dataset = g_dataset_lookup (dataset_location);
779       if (dataset)
780 	retval = g_datalist_id_get_data (&dataset->datalist, key_id);
781     }
782   G_UNLOCK (g_dataset_global);
783 
784   return retval;
785 }
786 
787 /**
788  * g_datalist_id_get_data:
789  * @datalist: a datalist.
790  * @key_id: the #GQuark identifying a data element.
791  *
792  * Retrieves the data element corresponding to @key_id.
793  *
794  * Returns: (transfer none) (nullable): the data element, or %NULL if
795  *          it is not found.
796  */
797 gpointer
g_datalist_id_get_data(GData ** datalist,GQuark key_id)798 g_datalist_id_get_data (GData  **datalist,
799 			GQuark   key_id)
800 {
801   return g_datalist_id_dup_data (datalist, key_id, NULL, NULL);
802 }
803 
804 /**
805  * GDuplicateFunc:
806  * @data: the data to duplicate
807  * @user_data: (closure): user data that was specified in
808  *             g_datalist_id_dup_data()
809  *
810  * The type of functions that are used to 'duplicate' an object.
811  * What this means depends on the context, it could just be
812  * incrementing the reference count, if @data is a ref-counted
813  * object.
814  *
815  * Returns: a duplicate of data
816  */
817 
818 /**
819  * g_datalist_id_dup_data: (skip)
820  * @datalist: location of a datalist
821  * @key_id: the #GQuark identifying a data element
822  * @dup_func: (nullable) (scope call): function to duplicate the old value
823  * @user_data: (closure): passed as user_data to @dup_func
824  *
825  * This is a variant of g_datalist_id_get_data() which
826  * returns a 'duplicate' of the value. @dup_func defines the
827  * meaning of 'duplicate' in this context, it could e.g.
828  * take a reference on a ref-counted object.
829  *
830  * If the @key_id is not set in the datalist then @dup_func
831  * will be called with a %NULL argument.
832  *
833  * Note that @dup_func is called while the datalist is locked, so it
834  * is not allowed to read or modify the datalist.
835  *
836  * This function can be useful to avoid races when multiple
837  * threads are using the same datalist and the same key.
838  *
839  * Returns: (nullable): the result of calling @dup_func on the value
840  *     associated with @key_id in @datalist, or %NULL if not set.
841  *     If @dup_func is %NULL, the value is returned unmodified.
842  *
843  * Since: 2.34
844  */
845 gpointer
g_datalist_id_dup_data(GData ** datalist,GQuark key_id,GDuplicateFunc dup_func,gpointer user_data)846 g_datalist_id_dup_data (GData          **datalist,
847                         GQuark           key_id,
848                         GDuplicateFunc   dup_func,
849                         gpointer         user_data)
850 {
851   gpointer val = NULL;
852   gpointer retval = NULL;
853   GData *d;
854   GDataElt *data, *data_end;
855 
856   g_datalist_lock (datalist);
857 
858   d = G_DATALIST_GET_POINTER (datalist);
859   if (d)
860     {
861       data = d->data;
862       data_end = data + d->len;
863       do
864         {
865           if (data->key == key_id)
866             {
867               val = data->data;
868               break;
869             }
870           data++;
871         }
872       while (data < data_end);
873     }
874 
875   if (dup_func)
876     retval = dup_func (val, user_data);
877   else
878     retval = val;
879 
880   g_datalist_unlock (datalist);
881 
882   return retval;
883 }
884 
885 /**
886  * g_datalist_id_replace_data: (skip)
887  * @datalist: location of a datalist
888  * @key_id: the #GQuark identifying a data element
889  * @oldval: (nullable): the old value to compare against
890  * @newval: (nullable): the new value to replace it with
891  * @destroy: (nullable): destroy notify for the new value
892  * @old_destroy: (out) (optional): destroy notify for the existing value
893  *
894  * Compares the member that is associated with @key_id in
895  * @datalist to @oldval, and if they are the same, replace
896  * @oldval with @newval.
897  *
898  * This is like a typical atomic compare-and-exchange
899  * operation, for a member of @datalist.
900  *
901  * If the previous value was replaced then ownership of the
902  * old value (@oldval) is passed to the caller, including
903  * the registered destroy notify for it (passed out in @old_destroy).
904  * Its up to the caller to free this as he wishes, which may
905  * or may not include using @old_destroy as sometimes replacement
906  * should not destroy the object in the normal way.
907  *
908  * Returns: %TRUE if the existing value for @key_id was replaced
909  *  by @newval, %FALSE otherwise.
910  *
911  * Since: 2.34
912  */
913 gboolean
g_datalist_id_replace_data(GData ** datalist,GQuark key_id,gpointer oldval,gpointer newval,GDestroyNotify destroy,GDestroyNotify * old_destroy)914 g_datalist_id_replace_data (GData          **datalist,
915                             GQuark           key_id,
916                             gpointer         oldval,
917                             gpointer         newval,
918                             GDestroyNotify   destroy,
919                             GDestroyNotify  *old_destroy)
920 {
921   gpointer val = NULL;
922   GData *d;
923   GDataElt *data, *data_end;
924 
925   g_return_val_if_fail (datalist != NULL, FALSE);
926   g_return_val_if_fail (key_id != 0, FALSE);
927 
928   if (old_destroy)
929     *old_destroy = NULL;
930 
931   g_datalist_lock (datalist);
932 
933   d = G_DATALIST_GET_POINTER (datalist);
934   if (d)
935     {
936       data = d->data;
937       data_end = data + d->len - 1;
938       while (data <= data_end)
939         {
940           if (data->key == key_id)
941             {
942               val = data->data;
943               if (val == oldval)
944                 {
945                   if (old_destroy)
946                     *old_destroy = data->destroy;
947                   if (newval != NULL)
948                     {
949                       data->data = newval;
950                       data->destroy = destroy;
951                     }
952                   else
953                    {
954                      if (data != data_end)
955                        *data = *data_end;
956                      d->len--;
957 
958                      /* We don't bother to shrink, but if all data are now gone
959                       * we at least free the memory
960                       */
961                      if (d->len == 0)
962                        {
963                          G_DATALIST_SET_POINTER (datalist, NULL);
964                          g_free (d);
965                        }
966                    }
967                 }
968               break;
969             }
970           data++;
971         }
972     }
973 
974   if (val == NULL && oldval == NULL && newval != NULL)
975     {
976       GData *old_d;
977 
978       /* insert newval */
979       old_d = d;
980       if (d == NULL)
981 	{
982           d = g_malloc (sizeof (GData));
983           d->len = 0;
984           d->alloc = 1;
985         }
986       else if (d->len == d->alloc)
987         {
988           d->alloc = d->alloc * 2;
989           d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt));
990         }
991       if (old_d != d)
992         G_DATALIST_SET_POINTER (datalist, d);
993 
994       d->data[d->len].key = key_id;
995       d->data[d->len].data = newval;
996       d->data[d->len].destroy = destroy;
997       d->len++;
998     }
999 
1000   g_datalist_unlock (datalist);
1001 
1002   return val == oldval;
1003 }
1004 
1005 /**
1006  * g_datalist_get_data:
1007  * @datalist: a datalist.
1008  * @key: the string identifying a data element.
1009  *
1010  * Gets a data element, using its string identifier. This is slower than
1011  * g_datalist_id_get_data() because it compares strings.
1012  *
1013  * Returns: (transfer none) (nullable): the data element, or %NULL if it
1014  *          is not found.
1015  **/
1016 gpointer
g_datalist_get_data(GData ** datalist,const gchar * key)1017 g_datalist_get_data (GData	 **datalist,
1018 		     const gchar *key)
1019 {
1020   gpointer res = NULL;
1021   GData *d;
1022   GDataElt *data, *data_end;
1023 
1024   g_return_val_if_fail (datalist != NULL, NULL);
1025 
1026   g_datalist_lock (datalist);
1027 
1028   d = G_DATALIST_GET_POINTER (datalist);
1029   if (d)
1030     {
1031       data = d->data;
1032       data_end = data + d->len;
1033       while (data < data_end)
1034 	{
1035 	  if (g_strcmp0 (g_quark_to_string (data->key), key) == 0)
1036 	    {
1037 	      res = data->data;
1038 	      break;
1039 	    }
1040 	  data++;
1041 	}
1042     }
1043 
1044   g_datalist_unlock (datalist);
1045 
1046   return res;
1047 }
1048 
1049 /**
1050  * GDataForeachFunc:
1051  * @key_id: the #GQuark id to identifying the data element.
1052  * @data: the data element.
1053  * @user_data: (closure): user data passed to g_dataset_foreach().
1054  *
1055  * Specifies the type of function passed to g_dataset_foreach(). It is
1056  * called with each #GQuark id and associated data element, together
1057  * with the @user_data parameter supplied to g_dataset_foreach().
1058  **/
1059 
1060 /**
1061  * g_dataset_foreach:
1062  * @dataset_location: (not nullable): the location identifying the dataset.
1063  * @func: (scope call): the function to call for each data element.
1064  * @user_data: (closure): user data to pass to the function.
1065  *
1066  * Calls the given function for each data element which is associated
1067  * with the given location. Note that this function is NOT thread-safe.
1068  * So unless @dataset_location can be protected from any modifications
1069  * during invocation of this function, it should not be called.
1070  *
1071  * @func can make changes to the dataset, but the iteration will not
1072  * reflect changes made during the g_dataset_foreach() call, other
1073  * than skipping over elements that are removed.
1074  **/
1075 void
g_dataset_foreach(gconstpointer dataset_location,GDataForeachFunc func,gpointer user_data)1076 g_dataset_foreach (gconstpointer    dataset_location,
1077 		   GDataForeachFunc func,
1078 		   gpointer         user_data)
1079 {
1080   GDataset *dataset;
1081 
1082   g_return_if_fail (dataset_location != NULL);
1083   g_return_if_fail (func != NULL);
1084 
1085   G_LOCK (g_dataset_global);
1086   if (g_dataset_location_ht)
1087     {
1088       dataset = g_dataset_lookup (dataset_location);
1089       G_UNLOCK (g_dataset_global);
1090       if (dataset)
1091 	g_datalist_foreach (&dataset->datalist, func, user_data);
1092     }
1093   else
1094     {
1095       G_UNLOCK (g_dataset_global);
1096     }
1097 }
1098 
1099 /**
1100  * g_datalist_foreach:
1101  * @datalist: a datalist.
1102  * @func: (scope call): the function to call for each data element.
1103  * @user_data: (closure): user data to pass to the function.
1104  *
1105  * Calls the given function for each data element of the datalist. The
1106  * function is called with each data element's #GQuark id and data,
1107  * together with the given @user_data parameter. Note that this
1108  * function is NOT thread-safe. So unless @datalist can be protected
1109  * from any modifications during invocation of this function, it should
1110  * not be called.
1111  *
1112  * @func can make changes to @datalist, but the iteration will not
1113  * reflect changes made during the g_datalist_foreach() call, other
1114  * than skipping over elements that are removed.
1115  **/
1116 void
g_datalist_foreach(GData ** datalist,GDataForeachFunc func,gpointer user_data)1117 g_datalist_foreach (GData	   **datalist,
1118 		    GDataForeachFunc func,
1119 		    gpointer         user_data)
1120 {
1121   GData *d;
1122   guint i, j, len;
1123   GQuark *keys;
1124 
1125   g_return_if_fail (datalist != NULL);
1126   g_return_if_fail (func != NULL);
1127 
1128   d = G_DATALIST_GET_POINTER (datalist);
1129   if (d == NULL)
1130     return;
1131 
1132   /* We make a copy of the keys so that we can handle it changing
1133      in the callback */
1134   len = d->len;
1135   keys = g_new (GQuark, len);
1136   for (i = 0; i < len; i++)
1137     keys[i] = d->data[i].key;
1138 
1139   for (i = 0; i < len; i++)
1140     {
1141       /* A previous callback might have removed a later item, so always check that
1142 	 it still exists before calling */
1143       d = G_DATALIST_GET_POINTER (datalist);
1144 
1145       if (d == NULL)
1146 	break;
1147       for (j = 0; j < d->len; j++)
1148 	{
1149 	  if (d->data[j].key == keys[i]) {
1150 	    func (d->data[i].key, d->data[i].data, user_data);
1151 	    break;
1152 	  }
1153 	}
1154     }
1155   g_free (keys);
1156 }
1157 
1158 /**
1159  * g_datalist_init: (skip)
1160  * @datalist: a pointer to a pointer to a datalist.
1161  *
1162  * Resets the datalist to %NULL. It does not free any memory or call
1163  * any destroy functions.
1164  **/
1165 void
g_datalist_init(GData ** datalist)1166 g_datalist_init (GData **datalist)
1167 {
1168   g_return_if_fail (datalist != NULL);
1169 
1170   g_atomic_pointer_set (datalist, NULL);
1171 }
1172 
1173 /**
1174  * g_datalist_set_flags:
1175  * @datalist: pointer to the location that holds a list
1176  * @flags: the flags to turn on. The values of the flags are
1177  *   restricted by %G_DATALIST_FLAGS_MASK (currently
1178  *   3; giving two possible boolean flags).
1179  *   A value for @flags that doesn't fit within the mask is
1180  *   an error.
1181  *
1182  * Turns on flag values for a data list. This function is used
1183  * to keep a small number of boolean flags in an object with
1184  * a data list without using any additional space. It is
1185  * not generally useful except in circumstances where space
1186  * is very tight. (It is used in the base #GObject type, for
1187  * example.)
1188  *
1189  * Since: 2.8
1190  **/
1191 void
g_datalist_set_flags(GData ** datalist,guint flags)1192 g_datalist_set_flags (GData **datalist,
1193 		      guint   flags)
1194 {
1195   g_return_if_fail (datalist != NULL);
1196   g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
1197 
1198   g_atomic_pointer_or (datalist, (gsize)flags);
1199 }
1200 
1201 /**
1202  * g_datalist_unset_flags:
1203  * @datalist: pointer to the location that holds a list
1204  * @flags: the flags to turn off. The values of the flags are
1205  *   restricted by %G_DATALIST_FLAGS_MASK (currently
1206  *   3: giving two possible boolean flags).
1207  *   A value for @flags that doesn't fit within the mask is
1208  *   an error.
1209  *
1210  * Turns off flag values for a data list. See g_datalist_unset_flags()
1211  *
1212  * Since: 2.8
1213  **/
1214 void
g_datalist_unset_flags(GData ** datalist,guint flags)1215 g_datalist_unset_flags (GData **datalist,
1216 			guint   flags)
1217 {
1218   g_return_if_fail (datalist != NULL);
1219   g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
1220 
1221   g_atomic_pointer_and (datalist, ~(gsize)flags);
1222 }
1223 
1224 /**
1225  * g_datalist_get_flags:
1226  * @datalist: pointer to the location that holds a list
1227  *
1228  * Gets flags values packed in together with the datalist.
1229  * See g_datalist_set_flags().
1230  *
1231  * Returns: the flags of the datalist
1232  *
1233  * Since: 2.8
1234  **/
1235 guint
g_datalist_get_flags(GData ** datalist)1236 g_datalist_get_flags (GData **datalist)
1237 {
1238   g_return_val_if_fail (datalist != NULL, 0);
1239 
1240   return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
1241 }
1242 
1243 /* HOLDS: g_dataset_global_lock */
1244 static void
g_data_initialize(void)1245 g_data_initialize (void)
1246 {
1247   g_return_if_fail (g_dataset_location_ht == NULL);
1248 
1249   g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
1250   g_dataset_cached = NULL;
1251 }
1252