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()
38 #include "gdatasetprivate.h"
43 #define G_QUARK_BLOCK_SIZE (512)
45 /* datalist pointer accesses have to be carried out atomically */
46 #define G_DATALIST_GET_POINTER(datalist) \
47 ((GData*) ((gsize) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK))
49 #define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \
50 gpointer _oldv, _newv; \
52 _oldv = g_atomic_pointer_get (datalist); \
53 _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK) | (gsize) pointer); \
54 } while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, _oldv, _newv)); \
57 /* --- structures --- */
58 typedef struct _GDataset GDataset;
64 GDestroyNotify destroy_func;
69 gconstpointer location;
74 /* --- prototypes --- */
75 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
76 static inline void g_datalist_clear_i (GData **datalist);
77 static void g_dataset_destroy_internal (GDataset *dataset);
78 static inline gpointer g_data_set_internal (GData **datalist,
81 GDestroyNotify destroy_func,
83 static void g_data_initialize (void);
84 static inline GQuark g_quark_new (gchar *string);
87 /* --- variables --- */
88 G_LOCK_DEFINE_STATIC (g_dataset_global);
89 static GHashTable *g_dataset_location_ht = NULL;
90 static GDataset *g_dataset_cached = NULL; /* should this be
92 G_LOCK_DEFINE_STATIC (g_quark_global);
93 static GHashTable *g_quark_ht = NULL;
94 static gchar **g_quarks = NULL;
95 static GQuark g_quark_seq_id = 0;
97 /* --- functions --- */
99 /* HOLDS: g_dataset_global_lock */
101 g_datalist_clear_i (GData **datalist)
103 register GData *list;
105 /* unlink *all* items before walking their destructors
107 list = G_DATALIST_GET_POINTER (datalist);
108 G_DATALIST_SET_POINTER (datalist, NULL);
112 register GData *prev;
117 if (prev->destroy_func)
119 G_UNLOCK (g_dataset_global);
120 prev->destroy_func (prev->data);
121 G_LOCK (g_dataset_global);
124 g_slice_free (GData, prev);
129 g_datalist_clear (GData **datalist)
131 g_return_if_fail (datalist != NULL);
133 G_LOCK (g_dataset_global);
134 if (!g_dataset_location_ht)
135 g_data_initialize ();
137 while (G_DATALIST_GET_POINTER (datalist))
138 g_datalist_clear_i (datalist);
139 G_UNLOCK (g_dataset_global);
142 /* HOLDS: g_dataset_global_lock */
143 static inline GDataset*
144 g_dataset_lookup (gconstpointer dataset_location)
146 register GDataset *dataset;
148 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
149 return g_dataset_cached;
151 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
153 g_dataset_cached = dataset;
158 /* HOLDS: g_dataset_global_lock */
160 g_dataset_destroy_internal (GDataset *dataset)
162 register gconstpointer dataset_location;
164 dataset_location = dataset->location;
167 if (!dataset->datalist)
169 if (dataset == g_dataset_cached)
170 g_dataset_cached = NULL;
171 g_hash_table_remove (g_dataset_location_ht, dataset_location);
172 g_slice_free (GDataset, dataset);
176 g_datalist_clear_i (&dataset->datalist);
177 dataset = g_dataset_lookup (dataset_location);
182 g_dataset_destroy (gconstpointer dataset_location)
184 g_return_if_fail (dataset_location != NULL);
186 G_LOCK (g_dataset_global);
187 if (g_dataset_location_ht)
189 register GDataset *dataset;
191 dataset = g_dataset_lookup (dataset_location);
193 g_dataset_destroy_internal (dataset);
195 G_UNLOCK (g_dataset_global);
198 /* HOLDS: g_dataset_global_lock */
199 static inline gpointer
200 g_data_set_internal (GData **datalist,
203 GDestroyNotify destroy_func,
206 register GData *list;
208 list = G_DATALIST_GET_POINTER (datalist);
211 register GData *prev;
216 if (list->id == key_id)
218 gpointer ret_data = NULL;
221 prev->next = list->next;
224 G_DATALIST_SET_POINTER (datalist, list->next);
226 /* the dataset destruction *must* be done
227 * prior to invocation of the data destroy function
229 if (!list->next && dataset)
230 g_dataset_destroy_internal (dataset);
233 /* the GData struct *must* already be unlinked
234 * when invoking the destroy function.
235 * we use (data==NULL && destroy_func!=NULL) as
236 * a special hint combination to "steal"
237 * data without destroy notification
239 if (list->destroy_func && !destroy_func)
241 G_UNLOCK (g_dataset_global);
242 list->destroy_func (list->data);
243 G_LOCK (g_dataset_global);
246 ret_data = list->data;
248 g_slice_free (GData, list);
261 if (list->id == key_id)
263 if (!list->destroy_func)
266 list->destroy_func = destroy_func;
270 register GDestroyNotify dfunc;
271 register gpointer ddata;
273 dfunc = list->destroy_func;
276 list->destroy_func = destroy_func;
278 /* we need to have updated all structures prior to
279 * invocation of the destroy function
281 G_UNLOCK (g_dataset_global);
283 G_LOCK (g_dataset_global);
292 list = g_slice_new (GData);
293 list->next = G_DATALIST_GET_POINTER (datalist);
296 list->destroy_func = destroy_func;
297 G_DATALIST_SET_POINTER (datalist, list);
304 g_dataset_id_set_data_full (gconstpointer dataset_location,
307 GDestroyNotify destroy_func)
309 register GDataset *dataset;
311 g_return_if_fail (dataset_location != NULL);
313 g_return_if_fail (destroy_func == NULL);
317 g_return_if_fail (key_id > 0);
322 G_LOCK (g_dataset_global);
323 if (!g_dataset_location_ht)
324 g_data_initialize ();
326 dataset = g_dataset_lookup (dataset_location);
329 dataset = g_slice_new (GDataset);
330 dataset->location = dataset_location;
331 g_datalist_init (&dataset->datalist);
332 g_hash_table_insert (g_dataset_location_ht,
333 (gpointer) dataset->location,
337 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
338 G_UNLOCK (g_dataset_global);
342 g_datalist_id_set_data_full (GData **datalist,
345 GDestroyNotify destroy_func)
347 g_return_if_fail (datalist != NULL);
349 g_return_if_fail (destroy_func == NULL);
353 g_return_if_fail (key_id > 0);
358 G_LOCK (g_dataset_global);
359 if (!g_dataset_location_ht)
360 g_data_initialize ();
362 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
363 G_UNLOCK (g_dataset_global);
367 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
370 gpointer ret_data = NULL;
372 g_return_val_if_fail (dataset_location != NULL, NULL);
374 G_LOCK (g_dataset_global);
375 if (key_id && g_dataset_location_ht)
379 dataset = g_dataset_lookup (dataset_location);
381 ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
383 G_UNLOCK (g_dataset_global);
389 g_datalist_id_remove_no_notify (GData **datalist,
392 gpointer ret_data = NULL;
394 g_return_val_if_fail (datalist != NULL, NULL);
396 G_LOCK (g_dataset_global);
397 if (key_id && g_dataset_location_ht)
398 ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
399 G_UNLOCK (g_dataset_global);
405 g_dataset_id_get_data (gconstpointer dataset_location,
408 g_return_val_if_fail (dataset_location != NULL, NULL);
410 G_LOCK (g_dataset_global);
411 if (key_id && g_dataset_location_ht)
413 register GDataset *dataset;
415 dataset = g_dataset_lookup (dataset_location);
418 register GData *list;
420 for (list = dataset->datalist; list; list = list->next)
421 if (list->id == key_id)
423 G_UNLOCK (g_dataset_global);
428 G_UNLOCK (g_dataset_global);
434 g_datalist_id_get_data (GData **datalist,
437 gpointer data = NULL;
438 g_return_val_if_fail (datalist != NULL, NULL);
441 register GData *list;
442 G_LOCK (g_dataset_global);
443 for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
444 if (list->id == key_id)
449 G_UNLOCK (g_dataset_global);
455 g_dataset_foreach (gconstpointer dataset_location,
456 GDataForeachFunc func,
459 register GDataset *dataset;
461 g_return_if_fail (dataset_location != NULL);
462 g_return_if_fail (func != NULL);
464 G_LOCK (g_dataset_global);
465 if (g_dataset_location_ht)
467 dataset = g_dataset_lookup (dataset_location);
468 G_UNLOCK (g_dataset_global);
471 register GData *list, *next;
473 for (list = dataset->datalist; list; list = next)
476 func (list->id, list->data, user_data);
482 G_UNLOCK (g_dataset_global);
487 g_datalist_foreach (GData **datalist,
488 GDataForeachFunc func,
491 register GData *list, *next;
493 g_return_if_fail (datalist != NULL);
494 g_return_if_fail (func != NULL);
496 for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
499 func (list->id, list->data, user_data);
504 g_datalist_init (GData **datalist)
506 g_return_if_fail (datalist != NULL);
508 g_atomic_pointer_set (datalist, NULL);
512 * g_datalist_set_flags:
513 * @datalist: pointer to the location that holds a list
514 * @flags: the flags to turn on. The values of the flags are
515 * restricted by %G_DATALIST_FLAGS_MASK (currently
516 * 3; giving two possible boolean flags).
517 * A value for @flags that doesn't fit within the mask is
520 * Turns on flag values for a data list. This function is used
521 * to keep a small number of boolean flags in an object with
522 * a data list without using any additional space. It is
523 * not generally useful except in circumstances where space
524 * is very tight. (It is used in the base #GObject type, for
530 g_datalist_set_flags (GData **datalist,
534 g_return_if_fail (datalist != NULL);
535 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
539 oldvalue = g_atomic_pointer_get (datalist);
541 while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
542 (gpointer) ((gsize) oldvalue | flags)));
546 * g_datalist_unset_flags:
547 * @datalist: pointer to the location that holds a list
548 * @flags: the flags to turn off. The values of the flags are
549 * restricted by %G_DATALIST_FLAGS_MASK (currently
550 * 3: giving two possible boolean flags).
551 * A value for @flags that doesn't fit within the mask is
554 * Turns off flag values for a data list. See g_datalist_unset_flags()
559 g_datalist_unset_flags (GData **datalist,
563 g_return_if_fail (datalist != NULL);
564 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
568 oldvalue = g_atomic_pointer_get (datalist);
570 while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
571 (gpointer) ((gsize) oldvalue & ~(gsize) flags)));
575 * g_datalist_get_flags:
576 * @datalist: pointer to the location that holds a list
578 * Gets flags values packed in together with the datalist.
579 * See g_datalist_set_flags().
581 * Return value: the flags of the datalist
586 g_datalist_get_flags (GData **datalist)
588 g_return_val_if_fail (datalist != NULL, 0);
590 return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
593 /* HOLDS: g_dataset_global_lock */
595 g_data_initialize (void)
597 g_return_if_fail (g_dataset_location_ht == NULL);
599 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
600 g_dataset_cached = NULL;
604 g_quark_try_string (const gchar *string)
607 g_return_val_if_fail (string != NULL, 0);
609 G_LOCK (g_quark_global);
611 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
612 G_UNLOCK (g_quark_global);
617 /* HOLDS: g_quark_global_lock */
619 g_quark_from_string_internal (const gchar *string,
625 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
628 quark = g_quark_new (duplicate ? g_strdup (string) : (gchar *)string);
634 g_quark_from_string (const gchar *string)
641 G_LOCK (g_quark_global);
642 quark = g_quark_from_string_internal (string, TRUE);
643 G_UNLOCK (g_quark_global);
649 g_quark_from_static_string (const gchar *string)
656 G_LOCK (g_quark_global);
657 quark = g_quark_from_string_internal (string, FALSE);
658 G_UNLOCK (g_quark_global);
663 G_CONST_RETURN gchar*
664 g_quark_to_string (GQuark quark)
666 gchar* result = NULL;
668 G_LOCK (g_quark_global);
669 if (quark < g_quark_seq_id)
670 result = g_quarks[quark];
671 G_UNLOCK (g_quark_global);
676 /* HOLDS: g_quark_global_lock */
678 g_quark_new (gchar *string)
682 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
683 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
686 g_assert (g_quark_seq_id == 0);
687 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
688 g_quarks[g_quark_seq_id++] = NULL;
691 quark = g_quark_seq_id++;
692 g_quarks[quark] = string;
693 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
702 * Returns a canonical representation for @string. Interned strings can
703 * be compared for equality by comparing the pointers, instead of using strcmp().
705 * Returns: a canonical representation for the string
709 G_CONST_RETURN gchar*
710 g_intern_string (const gchar *string)
718 G_LOCK (g_quark_global);
719 quark = g_quark_from_string_internal (string, TRUE);
720 result = g_quarks[quark];
721 G_UNLOCK (g_quark_global);
727 * g_intern_static_string:
728 * @string: a static string
730 * Returns a canonical representation for @string. Interned strings can
731 * be compared for equality by comparing the pointers, instead of using strcmp().
732 * g_intern_static_string() does not copy the string, therefore @string must
733 * not be freed or modified.
735 * Returns: a canonical representation for the string
739 G_CONST_RETURN gchar*
740 g_intern_static_string (const gchar *string)
748 G_LOCK (g_quark_global);
749 quark = g_quark_from_string_internal (string, FALSE);
750 result = g_quarks[quark];
751 G_UNLOCK (g_quark_global);
758 #define __G_DATASET_C__
759 #include "galiasdef.c"