1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * gdataset.c: Generic dataset mechanism, similar to GtkObject data.
5 * Copyright (C) 1998 Tim Janik
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.
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.
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.
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/.
30 * MT safe ; except for g_data*_foreach()
39 #include "gdatasetprivate.h"
43 #define G_QUARK_BLOCK_SIZE (512)
45 /* datalist pointer modifications have to be done with the g_dataset_global mutex held */
46 #define G_DATALIST_GET_POINTER(datalist) \
47 ((GData*) ((gsize) *(datalist) & ~(gsize) G_DATALIST_FLAGS_MASK))
48 #define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \
49 *(datalist) = (GData*) (G_DATALIST_GET_FLAGS (datalist) | \
54 /* --- structures --- */
55 typedef struct _GDataset GDataset;
61 GDestroyNotify destroy_func;
66 gconstpointer location;
71 /* --- prototypes --- */
72 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
73 static inline void g_datalist_clear_i (GData **datalist);
74 static void g_dataset_destroy_internal (GDataset *dataset);
75 static inline gpointer g_data_set_internal (GData **datalist,
78 GDestroyNotify destroy_func,
80 static void g_data_initialize (void);
81 static inline GQuark g_quark_new (gchar *string);
84 /* --- variables --- */
85 G_LOCK_DEFINE_STATIC (g_dataset_global);
86 static GHashTable *g_dataset_location_ht = NULL;
87 static GDataset *g_dataset_cached = NULL; /* should this be
89 G_LOCK_DEFINE_STATIC (g_quark_global);
90 static GHashTable *g_quark_ht = NULL;
91 static gchar **g_quarks = NULL;
92 static GQuark g_quark_seq_id = 0;
94 /* --- functions --- */
96 /* HOLDS: g_dataset_global_lock */
98 g_datalist_clear_i (GData **datalist)
100 register GData *list;
102 /* unlink *all* items before walking their destructors
104 list = G_DATALIST_GET_POINTER (datalist);
105 G_DATALIST_SET_POINTER (datalist, NULL);
109 register GData *prev;
114 if (prev->destroy_func)
116 G_UNLOCK (g_dataset_global);
117 prev->destroy_func (prev->data);
118 G_LOCK (g_dataset_global);
121 g_slice_free (GData, prev);
126 g_datalist_clear (GData **datalist)
128 g_return_if_fail (datalist != NULL);
130 G_LOCK (g_dataset_global);
131 if (!g_dataset_location_ht)
132 g_data_initialize ();
134 while (G_DATALIST_GET_POINTER (datalist))
135 g_datalist_clear_i (datalist);
136 G_UNLOCK (g_dataset_global);
139 /* HOLDS: g_dataset_global_lock */
140 static inline GDataset*
141 g_dataset_lookup (gconstpointer dataset_location)
143 register GDataset *dataset;
145 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
146 return g_dataset_cached;
148 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
150 g_dataset_cached = dataset;
155 /* HOLDS: g_dataset_global_lock */
157 g_dataset_destroy_internal (GDataset *dataset)
159 register gconstpointer dataset_location;
161 dataset_location = dataset->location;
164 if (!dataset->datalist)
166 if (dataset == g_dataset_cached)
167 g_dataset_cached = NULL;
168 g_hash_table_remove (g_dataset_location_ht, dataset_location);
169 g_slice_free (GDataset, dataset);
173 g_datalist_clear_i (&dataset->datalist);
174 dataset = g_dataset_lookup (dataset_location);
179 g_dataset_destroy (gconstpointer dataset_location)
181 g_return_if_fail (dataset_location != NULL);
183 G_LOCK (g_dataset_global);
184 if (g_dataset_location_ht)
186 register GDataset *dataset;
188 dataset = g_dataset_lookup (dataset_location);
190 g_dataset_destroy_internal (dataset);
192 G_UNLOCK (g_dataset_global);
195 /* HOLDS: g_dataset_global_lock */
196 static inline gpointer
197 g_data_set_internal (GData **datalist,
200 GDestroyNotify destroy_func,
203 register GData *list;
205 list = G_DATALIST_GET_POINTER (datalist);
208 register GData *prev;
213 if (list->id == key_id)
215 gpointer ret_data = NULL;
218 prev->next = list->next;
221 G_DATALIST_SET_POINTER (datalist, list->next);
223 /* the dataset destruction *must* be done
224 * prior to invocation of the data destroy function
226 if (!list->next && dataset)
227 g_dataset_destroy_internal (dataset);
230 /* the GData struct *must* already be unlinked
231 * when invoking the destroy function.
232 * we use (data==NULL && destroy_func!=NULL) as
233 * a special hint combination to "steal"
234 * data without destroy notification
236 if (list->destroy_func && !destroy_func)
238 G_UNLOCK (g_dataset_global);
239 list->destroy_func (list->data);
240 G_LOCK (g_dataset_global);
243 ret_data = list->data;
245 g_slice_free (GData, list);
258 if (list->id == key_id)
260 if (!list->destroy_func)
263 list->destroy_func = destroy_func;
267 register GDestroyNotify dfunc;
268 register gpointer ddata;
270 dfunc = list->destroy_func;
273 list->destroy_func = destroy_func;
275 /* we need to have updated all structures prior to
276 * invocation of the destroy function
278 G_UNLOCK (g_dataset_global);
280 G_LOCK (g_dataset_global);
289 list = g_slice_new (GData);
290 list->next = G_DATALIST_GET_POINTER (datalist);
293 list->destroy_func = destroy_func;
294 G_DATALIST_SET_POINTER (datalist, list);
301 g_dataset_id_set_data_full (gconstpointer dataset_location,
304 GDestroyNotify destroy_func)
306 register GDataset *dataset;
308 g_return_if_fail (dataset_location != NULL);
310 g_return_if_fail (destroy_func == NULL);
314 g_return_if_fail (key_id > 0);
319 G_LOCK (g_dataset_global);
320 if (!g_dataset_location_ht)
321 g_data_initialize ();
323 dataset = g_dataset_lookup (dataset_location);
326 dataset = g_slice_new (GDataset);
327 dataset->location = dataset_location;
328 g_datalist_init (&dataset->datalist);
329 g_hash_table_insert (g_dataset_location_ht,
330 (gpointer) dataset->location,
334 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
335 G_UNLOCK (g_dataset_global);
339 g_datalist_id_set_data_full (GData **datalist,
342 GDestroyNotify destroy_func)
344 g_return_if_fail (datalist != NULL);
346 g_return_if_fail (destroy_func == NULL);
350 g_return_if_fail (key_id > 0);
355 G_LOCK (g_dataset_global);
356 if (!g_dataset_location_ht)
357 g_data_initialize ();
359 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
360 G_UNLOCK (g_dataset_global);
364 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
367 gpointer ret_data = NULL;
369 g_return_val_if_fail (dataset_location != NULL, NULL);
371 G_LOCK (g_dataset_global);
372 if (key_id && g_dataset_location_ht)
376 dataset = g_dataset_lookup (dataset_location);
378 ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
380 G_UNLOCK (g_dataset_global);
386 g_datalist_id_remove_no_notify (GData **datalist,
389 gpointer ret_data = NULL;
391 g_return_val_if_fail (datalist != NULL, NULL);
393 G_LOCK (g_dataset_global);
394 if (key_id && g_dataset_location_ht)
395 ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
396 G_UNLOCK (g_dataset_global);
402 g_dataset_id_get_data (gconstpointer dataset_location,
405 g_return_val_if_fail (dataset_location != NULL, NULL);
407 G_LOCK (g_dataset_global);
408 if (key_id && g_dataset_location_ht)
410 register GDataset *dataset;
412 dataset = g_dataset_lookup (dataset_location);
415 register GData *list;
417 for (list = dataset->datalist; list; list = list->next)
418 if (list->id == key_id)
420 G_UNLOCK (g_dataset_global);
425 G_UNLOCK (g_dataset_global);
431 g_datalist_id_get_data (GData **datalist,
434 gpointer data = NULL;
435 g_return_val_if_fail (datalist != NULL, NULL);
438 register GData *list;
439 G_LOCK (g_dataset_global);
440 for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
441 if (list->id == key_id)
446 G_UNLOCK (g_dataset_global);
452 g_dataset_foreach (gconstpointer dataset_location,
453 GDataForeachFunc func,
456 register GDataset *dataset;
458 g_return_if_fail (dataset_location != NULL);
459 g_return_if_fail (func != NULL);
461 G_LOCK (g_dataset_global);
462 if (g_dataset_location_ht)
464 dataset = g_dataset_lookup (dataset_location);
465 G_UNLOCK (g_dataset_global);
468 register GData *list, *next;
470 for (list = dataset->datalist; list; list = next)
473 func (list->id, list->data, user_data);
479 G_UNLOCK (g_dataset_global);
484 g_datalist_foreach (GData **datalist,
485 GDataForeachFunc func,
488 register GData *list, *next;
490 g_return_if_fail (datalist != NULL);
491 g_return_if_fail (func != NULL);
493 for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
496 func (list->id, list->data, user_data);
501 g_datalist_init (GData **datalist)
503 g_return_if_fail (datalist != NULL);
509 * g_datalist_set_flags:
510 * @datalist: pointer to the location that holds a list
511 * @flags: the flags to turn on. The values of the flags are
512 * restricted by %G_DATALIST_FLAGS_MASK (currently
513 * 3; giving two possible boolean flags).
514 * A value for @flags that doesn't fit within the mask is
517 * Turns on flag values for a data list. This function is used
518 * to keep a small number of boolean flags in an object with
519 * a data list without using any additional space. It is
520 * not generally useful except in circumstances where space
521 * is very tight. (It is used in the base #GObject type, for
525 g_datalist_set_flags (GData **datalist,
529 g_return_if_fail (datalist != NULL);
530 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
534 oldvalue = g_atomic_pointer_get (datalist);
536 while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
537 (gpointer) ((gsize) oldvalue | flags)));
541 * g_datalist_unset_flags:
542 * @datalist: pointer to the location that holds a list
543 * @flags: the flags to turn off. The values of the flags are
544 * restricted by %G_DATALIST_FLAGS_MASK (currently
545 * 3: giving two possible boolean flags).
546 * A value for @flags that doesn't fit within the mask is
549 * Turns off flag values for a data list. See g_datalist_unset_flags()
552 g_datalist_unset_flags (GData **datalist,
556 g_return_if_fail (datalist != NULL);
557 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
561 oldvalue = g_atomic_pointer_get (datalist);
563 while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
564 (gpointer) ((gsize) oldvalue & ~(gsize) flags)));
568 * g_datalist_get_flags:
569 * @datalist: pointer to the location that holds a list
571 * Gets flags values packed in together with the datalist.
572 * See g_datalist_set_flags().
574 * Return value: the flags of the datalist
577 g_datalist_get_flags (GData **datalist)
579 g_return_val_if_fail (datalist != NULL, 0);
581 return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
584 /* HOLDS: g_dataset_global_lock */
586 g_data_initialize (void)
588 g_return_if_fail (g_dataset_location_ht == NULL);
590 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
591 g_dataset_cached = NULL;
595 g_quark_try_string (const gchar *string)
598 g_return_val_if_fail (string != NULL, 0);
600 G_LOCK (g_quark_global);
602 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
603 G_UNLOCK (g_quark_global);
608 /* HOLDS: g_quark_global_lock */
610 g_quark_from_string_internal (const gchar *string,
616 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
619 quark = g_quark_new (duplicate ? g_strdup (string) : (gchar *)string);
625 g_quark_from_string (const gchar *string)
629 g_return_val_if_fail (string != NULL, 0);
631 G_LOCK (g_quark_global);
632 quark = g_quark_from_string_internal (string, TRUE);
633 G_UNLOCK (g_quark_global);
639 g_quark_from_static_string (const gchar *string)
643 g_return_val_if_fail (string != NULL, 0);
645 G_LOCK (g_quark_global);
646 quark = g_quark_from_string_internal (string, FALSE);
647 G_UNLOCK (g_quark_global);
652 G_CONST_RETURN gchar*
653 g_quark_to_string (GQuark quark)
655 gchar* result = NULL;
657 G_LOCK (g_quark_global);
658 if (quark < g_quark_seq_id)
659 result = g_quarks[quark];
660 G_UNLOCK (g_quark_global);
665 /* HOLDS: g_quark_global_lock */
667 g_quark_new (gchar *string)
671 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
672 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
675 g_assert (g_quark_seq_id == 0);
676 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
677 g_quarks[g_quark_seq_id++] = NULL;
680 quark = g_quark_seq_id++;
681 g_quarks[quark] = string;
682 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
691 * Returns a canonical representation for @string. Interned strings can
692 * be compared for equality by comparing the pointers, instead of using strcmp().
694 * Returns: a canonical representation for the string
698 G_CONST_RETURN gchar*
699 g_intern_string (const gchar *string)
707 G_LOCK (g_quark_global);
708 quark = g_quark_from_string_internal (string, TRUE);
709 result = g_quarks[quark];
710 G_UNLOCK (g_quark_global);
716 * g_intern_static_string:
717 * @string: a static string
719 * Returns a canonical representation for @string. Interned strings can
720 * be compared for equality by comparing the pointers, instead of using strcmp().
721 * g_intern_static_string() does not copy the string, therefore @string must
722 * not be freed or modified.
724 * Returns: a canonical representation for the string
728 G_CONST_RETURN gchar*
729 g_intern_static_string (const gchar *string)
737 G_LOCK (g_quark_global);
738 quark = g_quark_from_string_internal (string, FALSE);
739 result = g_quarks[quark];
740 G_UNLOCK (g_quark_global);
747 #define __G_DATASET_C__
748 #include "galiasdef.c"