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_MEM_CHUNK_PREALLOC (128)
45 #define G_DATA_CACHE_MAX (512)
46 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
48 /* datalist pointer modifications have to be done with the g_dataset_global mutex held */
49 #define G_DATALIST_GET_POINTER(datalist) \
50 ((GData*) ((gsize) *(datalist) & ~(gsize) G_DATALIST_FLAGS_MASK))
51 #define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \
52 *(datalist) = (GData*) (G_DATALIST_GET_FLAGS (datalist) | \
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 static GMemChunk *g_dataset_mem_chunk = NULL;
93 static GMemChunk *g_data_mem_chunk = NULL;
94 static GData *g_data_cache = NULL;
95 static guint g_data_cache_length = 0;
97 G_LOCK_DEFINE_STATIC (g_quark_global);
98 static GHashTable *g_quark_ht = NULL;
99 static gchar **g_quarks = NULL;
100 static GQuark g_quark_seq_id = 0;
102 /* --- functions --- */
104 /* HOLDS: g_dataset_global_lock */
106 g_datalist_clear_i (GData **datalist)
108 register GData *list;
110 /* unlink *all* items before walking their destructors
112 list = G_DATALIST_GET_POINTER (datalist);
113 G_DATALIST_SET_POINTER (datalist, NULL);
117 register GData *prev;
122 if (prev->destroy_func)
124 G_UNLOCK (g_dataset_global);
125 prev->destroy_func (prev->data);
126 G_LOCK (g_dataset_global);
129 if (g_data_cache_length < G_DATA_CACHE_MAX)
131 prev->next = g_data_cache;
133 g_data_cache_length++;
136 g_mem_chunk_free (g_data_mem_chunk, prev);
141 g_datalist_clear (GData **datalist)
143 g_return_if_fail (datalist != NULL);
145 G_LOCK (g_dataset_global);
146 if (!g_dataset_location_ht)
147 g_data_initialize ();
149 while (G_DATALIST_GET_POINTER (datalist))
150 g_datalist_clear_i (datalist);
151 G_UNLOCK (g_dataset_global);
154 /* HOLDS: g_dataset_global_lock */
155 static inline GDataset*
156 g_dataset_lookup (gconstpointer dataset_location)
158 register GDataset *dataset;
160 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
161 return g_dataset_cached;
163 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
165 g_dataset_cached = dataset;
170 /* HOLDS: g_dataset_global_lock */
172 g_dataset_destroy_internal (GDataset *dataset)
174 register gconstpointer dataset_location;
176 dataset_location = dataset->location;
179 if (!dataset->datalist)
181 if (dataset == g_dataset_cached)
182 g_dataset_cached = NULL;
183 g_hash_table_remove (g_dataset_location_ht, dataset_location);
184 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
188 g_datalist_clear_i (&dataset->datalist);
189 dataset = g_dataset_lookup (dataset_location);
194 g_dataset_destroy (gconstpointer dataset_location)
196 g_return_if_fail (dataset_location != NULL);
198 G_LOCK (g_dataset_global);
199 if (g_dataset_location_ht)
201 register GDataset *dataset;
203 dataset = g_dataset_lookup (dataset_location);
205 g_dataset_destroy_internal (dataset);
207 G_UNLOCK (g_dataset_global);
210 /* HOLDS: g_dataset_global_lock */
211 static inline gpointer
212 g_data_set_internal (GData **datalist,
215 GDestroyNotify destroy_func,
218 register GData *list;
220 list = G_DATALIST_GET_POINTER (datalist);
223 register GData *prev;
228 if (list->id == key_id)
230 gpointer ret_data = NULL;
233 prev->next = list->next;
236 G_DATALIST_SET_POINTER (datalist, list->next);
238 /* the dataset destruction *must* be done
239 * prior to invocation of the data destroy function
241 if (!list->next && dataset)
242 g_dataset_destroy_internal (dataset);
245 /* the GData struct *must* already be unlinked
246 * when invoking the destroy function.
247 * we use (data==NULL && destroy_func!=NULL) as
248 * a special hint combination to "steal"
249 * data without destroy notification
251 if (list->destroy_func && !destroy_func)
253 G_UNLOCK (g_dataset_global);
254 list->destroy_func (list->data);
255 G_LOCK (g_dataset_global);
258 ret_data = list->data;
260 if (g_data_cache_length < G_DATA_CACHE_MAX)
262 list->next = g_data_cache;
264 g_data_cache_length++;
267 g_mem_chunk_free (g_data_mem_chunk, list);
280 if (list->id == key_id)
282 if (!list->destroy_func)
285 list->destroy_func = destroy_func;
289 register GDestroyNotify dfunc;
290 register gpointer ddata;
292 dfunc = list->destroy_func;
295 list->destroy_func = destroy_func;
297 /* we need to have updated all structures prior to
298 * invocation of the destroy function
300 G_UNLOCK (g_dataset_global);
302 G_LOCK (g_dataset_global);
314 g_data_cache = list->next;
315 g_data_cache_length--;
318 list = g_chunk_new (GData, g_data_mem_chunk);
319 list->next = G_DATALIST_GET_POINTER (datalist);
322 list->destroy_func = destroy_func;
323 G_DATALIST_SET_POINTER (datalist, list);
330 g_dataset_id_set_data_full (gconstpointer dataset_location,
333 GDestroyNotify destroy_func)
335 register GDataset *dataset;
337 g_return_if_fail (dataset_location != NULL);
339 g_return_if_fail (destroy_func == NULL);
343 g_return_if_fail (key_id > 0);
348 G_LOCK (g_dataset_global);
349 if (!g_dataset_location_ht)
350 g_data_initialize ();
352 dataset = g_dataset_lookup (dataset_location);
355 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
356 dataset->location = dataset_location;
357 g_datalist_init (&dataset->datalist);
358 g_hash_table_insert (g_dataset_location_ht,
359 (gpointer) dataset->location,
363 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
364 G_UNLOCK (g_dataset_global);
368 g_datalist_id_set_data_full (GData **datalist,
371 GDestroyNotify destroy_func)
373 g_return_if_fail (datalist != NULL);
375 g_return_if_fail (destroy_func == NULL);
379 g_return_if_fail (key_id > 0);
384 G_LOCK (g_dataset_global);
385 if (!g_dataset_location_ht)
386 g_data_initialize ();
388 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
389 G_UNLOCK (g_dataset_global);
393 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
396 gpointer ret_data = NULL;
398 g_return_val_if_fail (dataset_location != NULL, NULL);
400 G_LOCK (g_dataset_global);
401 if (key_id && g_dataset_location_ht)
405 dataset = g_dataset_lookup (dataset_location);
407 ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
409 G_UNLOCK (g_dataset_global);
415 g_datalist_id_remove_no_notify (GData **datalist,
418 gpointer ret_data = NULL;
420 g_return_val_if_fail (datalist != NULL, NULL);
422 G_LOCK (g_dataset_global);
423 if (key_id && g_dataset_location_ht)
424 ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
425 G_UNLOCK (g_dataset_global);
431 g_dataset_id_get_data (gconstpointer dataset_location,
434 g_return_val_if_fail (dataset_location != NULL, NULL);
436 G_LOCK (g_dataset_global);
437 if (key_id && g_dataset_location_ht)
439 register GDataset *dataset;
441 dataset = g_dataset_lookup (dataset_location);
444 register GData *list;
446 for (list = dataset->datalist; list; list = list->next)
447 if (list->id == key_id)
449 G_UNLOCK (g_dataset_global);
454 G_UNLOCK (g_dataset_global);
460 g_datalist_id_get_data (GData **datalist,
463 gpointer data = NULL;
464 g_return_val_if_fail (datalist != NULL, NULL);
467 register GData *list;
468 G_LOCK (g_dataset_global);
469 for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
470 if (list->id == key_id)
475 G_UNLOCK (g_dataset_global);
481 g_dataset_foreach (gconstpointer dataset_location,
482 GDataForeachFunc func,
485 register GDataset *dataset;
487 g_return_if_fail (dataset_location != NULL);
488 g_return_if_fail (func != NULL);
490 G_LOCK (g_dataset_global);
491 if (g_dataset_location_ht)
493 dataset = g_dataset_lookup (dataset_location);
494 G_UNLOCK (g_dataset_global);
497 register GData *list, *next;
499 for (list = dataset->datalist; list; list = next)
502 func (list->id, list->data, user_data);
508 G_UNLOCK (g_dataset_global);
513 g_datalist_foreach (GData **datalist,
514 GDataForeachFunc func,
517 register GData *list, *next;
519 g_return_if_fail (datalist != NULL);
520 g_return_if_fail (func != NULL);
522 for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
525 func (list->id, list->data, user_data);
530 g_datalist_init (GData **datalist)
532 g_return_if_fail (datalist != NULL);
538 * g_datalist_set_flags:
539 * @datalist: pointer to the location that holds a list
540 * @flags: the flags to turn on. The values of the flags are
541 * restricted by %G_DATALIST_FLAGS_MASK (currently
542 * 3; giving two possible boolean flags).
543 * A value for @flags that doesn't fit within the mask is
546 * Turns on flag values for a data list. This function is used
547 * to keep a small number of boolean flags in an object with
548 * a data list without using any additional space. It is
549 * not generally useful except in circumstances where space
550 * is very tight. (It is used in the base #GObject type, for
554 g_datalist_set_flags (GData **datalist,
557 g_return_if_fail (datalist != NULL);
558 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
560 G_LOCK (g_dataset_global);
561 *datalist = (GData*) (flags | (gsize) *datalist);
562 G_UNLOCK (g_dataset_global);
566 * g_datalist_unset_flags:
567 * @datalist: pointer to the location that holds a list
568 * @flags: the flags to turn off. The values of the flags are
569 * restricted by %G_DATALIST_FLAGS_MASK (currently
570 * 3: giving two possible boolean flags).
571 * A value for @flags that doesn't fit within the mask is
574 * Turns off flag values for a data list. See g_datalist_unset_flags()
577 g_datalist_unset_flags (GData **datalist,
580 g_return_if_fail (datalist != NULL);
581 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
583 G_LOCK (g_dataset_global);
584 *datalist = (GData*) (~(gsize) flags & (gsize) *datalist);
585 G_UNLOCK (g_dataset_global);
589 * g_datalist_get_flags:
590 * @datalist: pointer to the location that holds a list
592 * Gets flags values packed in together with the datalist.
593 * See g_datalist_set_flags().
595 * Return value: the flags of the datalist
598 g_datalist_get_flags (GData **datalist)
600 g_return_val_if_fail (datalist != NULL, 0);
602 return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
605 /* HOLDS: g_dataset_global_lock */
607 g_data_initialize (void)
609 g_return_if_fail (g_dataset_location_ht == NULL);
611 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
612 g_dataset_cached = NULL;
613 g_dataset_mem_chunk =
614 g_mem_chunk_new ("GDataset MemChunk",
616 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
619 g_mem_chunk_new ("GData MemChunk",
621 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
626 g_quark_try_string (const gchar *string)
629 g_return_val_if_fail (string != NULL, 0);
631 G_LOCK (g_quark_global);
633 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
634 G_UNLOCK (g_quark_global);
640 g_quark_from_string (const gchar *string)
644 g_return_val_if_fail (string != NULL, 0);
646 G_LOCK (g_quark_global);
648 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
651 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
656 quark = g_quark_new (g_strdup (string));
657 G_UNLOCK (g_quark_global);
663 g_quark_from_static_string (const gchar *string)
667 g_return_val_if_fail (string != NULL, 0);
669 G_LOCK (g_quark_global);
671 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
674 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
679 quark = g_quark_new ((gchar*) string);
680 G_UNLOCK (g_quark_global);
685 G_CONST_RETURN gchar*
686 g_quark_to_string (GQuark quark)
688 gchar* result = NULL;
689 G_LOCK (g_quark_global);
690 if (quark > 0 && quark <= g_quark_seq_id)
691 result = g_quarks[quark - 1];
692 G_UNLOCK (g_quark_global);
697 /* HOLDS: g_quark_global_lock */
699 g_quark_new (gchar *string)
703 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
704 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
706 g_quarks[g_quark_seq_id] = string;
708 quark = g_quark_seq_id;
709 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
718 * Returns a canonical representation for @string. Interned strings can
719 * be compared for equality by comparing the pointers, instead of using strcmp().
721 * Returns: a canonical representation for the string
725 G_CONST_RETURN gchar*
726 g_intern_string (const gchar *string)
728 return string ? g_quark_to_string (g_quark_from_string (string)) : NULL;
732 * g_intern_static_string:
733 * @string: a static string
735 * Returns a canonical representation for @string. Interned strings can
736 * be compared for equality by comparing the pointers, instead of using strcmp().
737 * g_intern_static_string() does not copy the string, therefore @string must
738 * not be freed or modified.
740 * Returns: a canonical representation for the string
744 G_CONST_RETURN gchar*
745 g_intern_static_string (const gchar *string)
747 return string ? g_quark_to_string (g_quark_from_static_string (string)) : NULL;
752 #define __G_DATASET_C__
753 #include "galiasdef.c"