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