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)
44 #define G_DATA_CACHE_MAX (512)
46 /* datalist pointer modifications have to be done with the g_dataset_global mutex held */
47 #define G_DATALIST_GET_POINTER(datalist) \
48 ((GData*) ((gsize) *(datalist) & ~(gsize) G_DATALIST_FLAGS_MASK))
49 #define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \
50 *(datalist) = (GData*) (G_DATALIST_GET_FLAGS (datalist) | \
55 /* --- structures --- */
56 typedef struct _GDataset GDataset;
62 GDestroyNotify destroy_func;
67 gconstpointer location;
72 /* --- prototypes --- */
73 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
74 static inline void g_datalist_clear_i (GData **datalist);
75 static void g_dataset_destroy_internal (GDataset *dataset);
76 static inline gpointer g_data_set_internal (GData **datalist,
79 GDestroyNotify destroy_func,
81 static void g_data_initialize (void);
82 static inline GQuark g_quark_new (gchar *string);
85 /* --- variables --- */
86 G_LOCK_DEFINE_STATIC (g_dataset_global);
87 static GHashTable *g_dataset_location_ht = NULL;
88 static GDataset *g_dataset_cached = NULL; /* should this be
90 static GData *g_data_cache = NULL;
91 static guint g_data_cache_length = 0;
93 G_LOCK_DEFINE_STATIC (g_quark_global);
94 static GHashTable *g_quark_ht = NULL;
95 static gchar **g_quarks = NULL;
96 static GQuark g_quark_seq_id = 0;
98 /* --- functions --- */
100 /* HOLDS: g_dataset_global_lock */
102 g_datalist_clear_i (GData **datalist)
104 register GData *list;
106 /* unlink *all* items before walking their destructors
108 list = G_DATALIST_GET_POINTER (datalist);
109 G_DATALIST_SET_POINTER (datalist, NULL);
113 register GData *prev;
118 if (prev->destroy_func)
120 G_UNLOCK (g_dataset_global);
121 prev->destroy_func (prev->data);
122 G_LOCK (g_dataset_global);
125 if (g_data_cache_length < G_DATA_CACHE_MAX)
127 prev->next = g_data_cache;
129 g_data_cache_length++;
132 g_slice_free (GData, prev);
137 g_datalist_clear (GData **datalist)
139 g_return_if_fail (datalist != NULL);
141 G_LOCK (g_dataset_global);
142 if (!g_dataset_location_ht)
143 g_data_initialize ();
145 while (G_DATALIST_GET_POINTER (datalist))
146 g_datalist_clear_i (datalist);
147 G_UNLOCK (g_dataset_global);
150 /* HOLDS: g_dataset_global_lock */
151 static inline GDataset*
152 g_dataset_lookup (gconstpointer dataset_location)
154 register GDataset *dataset;
156 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
157 return g_dataset_cached;
159 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
161 g_dataset_cached = dataset;
166 /* HOLDS: g_dataset_global_lock */
168 g_dataset_destroy_internal (GDataset *dataset)
170 register gconstpointer dataset_location;
172 dataset_location = dataset->location;
175 if (!dataset->datalist)
177 if (dataset == g_dataset_cached)
178 g_dataset_cached = NULL;
179 g_hash_table_remove (g_dataset_location_ht, dataset_location);
180 g_slice_free (GDataset, dataset);
184 g_datalist_clear_i (&dataset->datalist);
185 dataset = g_dataset_lookup (dataset_location);
190 g_dataset_destroy (gconstpointer dataset_location)
192 g_return_if_fail (dataset_location != NULL);
194 G_LOCK (g_dataset_global);
195 if (g_dataset_location_ht)
197 register GDataset *dataset;
199 dataset = g_dataset_lookup (dataset_location);
201 g_dataset_destroy_internal (dataset);
203 G_UNLOCK (g_dataset_global);
206 /* HOLDS: g_dataset_global_lock */
207 static inline gpointer
208 g_data_set_internal (GData **datalist,
211 GDestroyNotify destroy_func,
214 register GData *list;
216 list = G_DATALIST_GET_POINTER (datalist);
219 register GData *prev;
224 if (list->id == key_id)
226 gpointer ret_data = NULL;
229 prev->next = list->next;
232 G_DATALIST_SET_POINTER (datalist, list->next);
234 /* the dataset destruction *must* be done
235 * prior to invocation of the data destroy function
237 if (!list->next && dataset)
238 g_dataset_destroy_internal (dataset);
241 /* the GData struct *must* already be unlinked
242 * when invoking the destroy function.
243 * we use (data==NULL && destroy_func!=NULL) as
244 * a special hint combination to "steal"
245 * data without destroy notification
247 if (list->destroy_func && !destroy_func)
249 G_UNLOCK (g_dataset_global);
250 list->destroy_func (list->data);
251 G_LOCK (g_dataset_global);
254 ret_data = list->data;
256 if (g_data_cache_length < G_DATA_CACHE_MAX)
258 list->next = g_data_cache;
260 g_data_cache_length++;
263 g_slice_free (GData, list);
276 if (list->id == key_id)
278 if (!list->destroy_func)
281 list->destroy_func = destroy_func;
285 register GDestroyNotify dfunc;
286 register gpointer ddata;
288 dfunc = list->destroy_func;
291 list->destroy_func = destroy_func;
293 /* we need to have updated all structures prior to
294 * invocation of the destroy function
296 G_UNLOCK (g_dataset_global);
298 G_LOCK (g_dataset_global);
310 g_data_cache = list->next;
311 g_data_cache_length--;
314 list = g_slice_new (GData);
315 list->next = G_DATALIST_GET_POINTER (datalist);
318 list->destroy_func = destroy_func;
319 G_DATALIST_SET_POINTER (datalist, list);
326 g_dataset_id_set_data_full (gconstpointer dataset_location,
329 GDestroyNotify destroy_func)
331 register GDataset *dataset;
333 g_return_if_fail (dataset_location != NULL);
335 g_return_if_fail (destroy_func == NULL);
339 g_return_if_fail (key_id > 0);
344 G_LOCK (g_dataset_global);
345 if (!g_dataset_location_ht)
346 g_data_initialize ();
348 dataset = g_dataset_lookup (dataset_location);
351 dataset = g_slice_new (GDataset);
352 dataset->location = dataset_location;
353 g_datalist_init (&dataset->datalist);
354 g_hash_table_insert (g_dataset_location_ht,
355 (gpointer) dataset->location,
359 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
360 G_UNLOCK (g_dataset_global);
364 g_datalist_id_set_data_full (GData **datalist,
367 GDestroyNotify destroy_func)
369 g_return_if_fail (datalist != NULL);
371 g_return_if_fail (destroy_func == NULL);
375 g_return_if_fail (key_id > 0);
380 G_LOCK (g_dataset_global);
381 if (!g_dataset_location_ht)
382 g_data_initialize ();
384 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
385 G_UNLOCK (g_dataset_global);
389 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
392 gpointer ret_data = NULL;
394 g_return_val_if_fail (dataset_location != NULL, NULL);
396 G_LOCK (g_dataset_global);
397 if (key_id && g_dataset_location_ht)
401 dataset = g_dataset_lookup (dataset_location);
403 ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
405 G_UNLOCK (g_dataset_global);
411 g_datalist_id_remove_no_notify (GData **datalist,
414 gpointer ret_data = NULL;
416 g_return_val_if_fail (datalist != NULL, NULL);
418 G_LOCK (g_dataset_global);
419 if (key_id && g_dataset_location_ht)
420 ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
421 G_UNLOCK (g_dataset_global);
427 g_dataset_id_get_data (gconstpointer dataset_location,
430 g_return_val_if_fail (dataset_location != NULL, NULL);
432 G_LOCK (g_dataset_global);
433 if (key_id && g_dataset_location_ht)
435 register GDataset *dataset;
437 dataset = g_dataset_lookup (dataset_location);
440 register GData *list;
442 for (list = dataset->datalist; list; list = list->next)
443 if (list->id == key_id)
445 G_UNLOCK (g_dataset_global);
450 G_UNLOCK (g_dataset_global);
456 g_datalist_id_get_data (GData **datalist,
459 gpointer data = NULL;
460 g_return_val_if_fail (datalist != NULL, NULL);
463 register GData *list;
464 G_LOCK (g_dataset_global);
465 for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
466 if (list->id == key_id)
471 G_UNLOCK (g_dataset_global);
477 g_dataset_foreach (gconstpointer dataset_location,
478 GDataForeachFunc func,
481 register GDataset *dataset;
483 g_return_if_fail (dataset_location != NULL);
484 g_return_if_fail (func != NULL);
486 G_LOCK (g_dataset_global);
487 if (g_dataset_location_ht)
489 dataset = g_dataset_lookup (dataset_location);
490 G_UNLOCK (g_dataset_global);
493 register GData *list, *next;
495 for (list = dataset->datalist; list; list = next)
498 func (list->id, list->data, user_data);
504 G_UNLOCK (g_dataset_global);
509 g_datalist_foreach (GData **datalist,
510 GDataForeachFunc func,
513 register GData *list, *next;
515 g_return_if_fail (datalist != NULL);
516 g_return_if_fail (func != NULL);
518 for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
521 func (list->id, list->data, user_data);
526 g_datalist_init (GData **datalist)
528 g_return_if_fail (datalist != NULL);
534 * g_datalist_set_flags:
535 * @datalist: pointer to the location that holds a list
536 * @flags: the flags to turn on. The values of the flags are
537 * restricted by %G_DATALIST_FLAGS_MASK (currently
538 * 3; giving two possible boolean flags).
539 * A value for @flags that doesn't fit within the mask is
542 * Turns on flag values for a data list. This function is used
543 * to keep a small number of boolean flags in an object with
544 * a data list without using any additional space. It is
545 * not generally useful except in circumstances where space
546 * is very tight. (It is used in the base #GObject type, for
550 g_datalist_set_flags (GData **datalist,
553 g_return_if_fail (datalist != NULL);
554 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
556 G_LOCK (g_dataset_global);
557 *datalist = (GData*) (flags | (gsize) *datalist);
558 G_UNLOCK (g_dataset_global);
562 * g_datalist_unset_flags:
563 * @datalist: pointer to the location that holds a list
564 * @flags: the flags to turn off. The values of the flags are
565 * restricted by %G_DATALIST_FLAGS_MASK (currently
566 * 3: giving two possible boolean flags).
567 * A value for @flags that doesn't fit within the mask is
570 * Turns off flag values for a data list. See g_datalist_unset_flags()
573 g_datalist_unset_flags (GData **datalist,
576 g_return_if_fail (datalist != NULL);
577 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
579 G_LOCK (g_dataset_global);
580 *datalist = (GData*) (~(gsize) flags & (gsize) *datalist);
581 G_UNLOCK (g_dataset_global);
585 * g_datalist_get_flags:
586 * @datalist: pointer to the location that holds a list
588 * Gets flags values packed in together with the datalist.
589 * See g_datalist_set_flags().
591 * Return value: the flags of the datalist
594 g_datalist_get_flags (GData **datalist)
596 g_return_val_if_fail (datalist != NULL, 0);
598 return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
601 /* HOLDS: g_dataset_global_lock */
603 g_data_initialize (void)
605 g_return_if_fail (g_dataset_location_ht == NULL);
607 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
608 g_dataset_cached = NULL;
612 g_quark_try_string (const gchar *string)
615 g_return_val_if_fail (string != NULL, 0);
617 G_LOCK (g_quark_global);
619 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
620 G_UNLOCK (g_quark_global);
625 /* HOLDS: g_quark_global_lock */
627 g_quark_from_string_internal (const gchar *string,
633 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
636 quark = g_quark_new (duplicate ? g_strdup (string) : (gchar *)string);
642 g_quark_from_string (const gchar *string)
646 g_return_val_if_fail (string != NULL, 0);
648 G_LOCK (g_quark_global);
649 quark = g_quark_from_string_internal (string, TRUE);
650 G_UNLOCK (g_quark_global);
656 g_quark_from_static_string (const gchar *string)
660 g_return_val_if_fail (string != NULL, 0);
662 G_LOCK (g_quark_global);
663 quark = g_quark_from_string_internal (string, FALSE);
664 G_UNLOCK (g_quark_global);
669 G_CONST_RETURN gchar*
670 g_quark_to_string (GQuark quark)
672 gchar* result = NULL;
674 G_LOCK (g_quark_global);
675 if (quark > 0 && quark <= g_quark_seq_id)
676 result = g_quarks[quark];
677 G_UNLOCK (g_quark_global);
682 /* HOLDS: g_quark_global_lock */
684 g_quark_new (gchar *string)
688 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
689 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
693 g_quarks[g_quark_seq_id] = string;
694 quark = g_quark_seq_id;
697 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
699 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
708 * Returns a canonical representation for @string. Interned strings can
709 * be compared for equality by comparing the pointers, instead of using strcmp().
711 * Returns: a canonical representation for the string
715 G_CONST_RETURN gchar*
716 g_intern_string (const gchar *string)
724 G_LOCK (g_quark_global);
725 quark = g_quark_from_string_internal (string, TRUE);
726 result = g_quarks[quark];
727 G_UNLOCK (g_quark_global);
733 * g_intern_static_string:
734 * @string: a static string
736 * Returns a canonical representation for @string. Interned strings can
737 * be compared for equality by comparing the pointers, instead of using strcmp().
738 * g_intern_static_string() does not copy the string, therefore @string must
739 * not be freed or modified.
741 * Returns: a canonical representation for the string
745 G_CONST_RETURN gchar*
746 g_intern_static_string (const gchar *string)
754 G_LOCK (g_quark_global);
755 quark = g_quark_from_string_internal (string, FALSE);
756 result = g_quarks[quark];
757 G_UNLOCK (g_quark_global);
764 #define __G_DATASET_C__
765 #include "galiasdef.c"