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 ; FIXME: might still freeze, watch out, not thoroughly
40 #include "gdatasetprivate.h"
44 #define G_QUARK_BLOCK_SIZE (512)
45 #define G_DATA_MEM_CHUNK_PREALLOC (128)
46 #define G_DATA_CACHE_MAX (512)
47 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
50 /* --- structures --- */
51 typedef struct _GDataset GDataset;
57 GDestroyNotify destroy_func;
62 gconstpointer location;
67 /* --- prototypes --- */
68 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
69 static inline void g_datalist_clear_i (GData **datalist);
70 static void g_dataset_destroy_internal (GDataset *dataset);
71 static inline gpointer g_data_set_internal (GData **datalist,
74 GDestroyNotify destroy_func,
76 static void g_data_initialize (void);
77 static inline GQuark g_quark_new (gchar *string);
80 /* --- variables --- */
81 G_LOCK_DEFINE_STATIC (g_dataset_global);
82 static GHashTable *g_dataset_location_ht = NULL;
83 static GDataset *g_dataset_cached = NULL; /* should this be
85 static GMemChunk *g_dataset_mem_chunk = NULL;
86 static GMemChunk *g_data_mem_chunk = NULL;
87 static GData *g_data_cache = NULL;
88 static guint g_data_cache_length = 0;
90 G_LOCK_DEFINE_STATIC (g_quark_global);
91 static GHashTable *g_quark_ht = NULL;
92 static gchar **g_quarks = NULL;
93 static GQuark g_quark_seq_id = 0;
95 /* --- functions --- */
97 /* HOLDS: g_dataset_global_lock */
99 g_datalist_clear_i (GData **datalist)
101 register GData *list;
103 /* unlink *all* items before walking their destructors
105 list = G_DATALIST_GET_POINTER (datalist);
106 G_DATALIST_SET_POINTER (datalist, NULL);
110 register GData *prev;
115 if (prev->destroy_func)
117 G_UNLOCK (g_dataset_global);
118 prev->destroy_func (prev->data);
119 G_LOCK (g_dataset_global);
122 if (g_data_cache_length < G_DATA_CACHE_MAX)
124 prev->next = g_data_cache;
126 g_data_cache_length++;
129 g_mem_chunk_free (g_data_mem_chunk, prev);
134 g_datalist_clear (GData **datalist)
136 g_return_if_fail (datalist != NULL);
138 G_LOCK (g_dataset_global);
139 if (!g_dataset_location_ht)
140 g_data_initialize ();
142 while (G_DATALIST_GET_POINTER (datalist))
143 g_datalist_clear_i (datalist);
144 G_UNLOCK (g_dataset_global);
147 /* HOLDS: g_dataset_global_lock */
148 static inline GDataset*
149 g_dataset_lookup (gconstpointer dataset_location)
151 register GDataset *dataset;
153 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
154 return g_dataset_cached;
156 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
158 g_dataset_cached = dataset;
163 /* HOLDS: g_dataset_global_lock */
165 g_dataset_destroy_internal (GDataset *dataset)
167 register gconstpointer dataset_location;
169 dataset_location = dataset->location;
172 if (!dataset->datalist)
174 if (dataset == g_dataset_cached)
175 g_dataset_cached = NULL;
176 g_hash_table_remove (g_dataset_location_ht, dataset_location);
177 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
181 g_datalist_clear_i (&dataset->datalist);
182 dataset = g_dataset_lookup (dataset_location);
187 g_dataset_destroy (gconstpointer dataset_location)
189 g_return_if_fail (dataset_location != NULL);
191 G_LOCK (g_dataset_global);
192 if (g_dataset_location_ht)
194 register GDataset *dataset;
196 dataset = g_dataset_lookup (dataset_location);
198 g_dataset_destroy_internal (dataset);
200 G_UNLOCK (g_dataset_global);
203 /* HOLDS: g_dataset_global_lock */
204 static inline gpointer
205 g_data_set_internal (GData **datalist,
208 GDestroyNotify destroy_func,
211 register GData *list;
213 list = G_DATALIST_GET_POINTER (datalist);
216 register GData *prev;
221 if (list->id == key_id)
223 gpointer ret_data = NULL;
226 prev->next = list->next;
229 G_DATALIST_SET_POINTER (datalist, list->next);
231 /* the dataset destruction *must* be done
232 * prior to invokation of the data destroy function
234 if (!list->next && dataset)
235 g_dataset_destroy_internal (dataset);
238 /* the GData struct *must* already be unlinked
239 * when invoking the destroy function.
240 * we use (data==NULL && destroy_func!=NULL) as
241 * a special hint combination to "steal"
242 * data without destroy notification
244 if (list->destroy_func && !destroy_func)
246 G_UNLOCK (g_dataset_global);
247 list->destroy_func (list->data);
248 G_LOCK (g_dataset_global);
251 ret_data = list->data;
253 if (g_data_cache_length < G_DATA_CACHE_MAX)
255 list->next = g_data_cache;
257 g_data_cache_length++;
260 g_mem_chunk_free (g_data_mem_chunk, list);
273 if (list->id == key_id)
275 if (!list->destroy_func)
278 list->destroy_func = destroy_func;
282 register GDestroyNotify dfunc;
283 register gpointer ddata;
285 dfunc = list->destroy_func;
288 list->destroy_func = destroy_func;
290 /* we need to have updated all structures prior to
291 * invokation of the destroy function
293 G_UNLOCK (g_dataset_global);
295 G_LOCK (g_dataset_global);
307 g_data_cache = list->next;
308 g_data_cache_length--;
311 list = g_chunk_new (GData, g_data_mem_chunk);
312 list->next = G_DATALIST_GET_POINTER (datalist);
315 list->destroy_func = destroy_func;
316 G_DATALIST_SET_POINTER (datalist, list);
323 g_dataset_id_set_data_full (gconstpointer dataset_location,
326 GDestroyNotify destroy_func)
328 register GDataset *dataset;
330 g_return_if_fail (dataset_location != NULL);
332 g_return_if_fail (destroy_func == NULL);
336 g_return_if_fail (key_id > 0);
341 G_LOCK (g_dataset_global);
342 if (!g_dataset_location_ht)
343 g_data_initialize ();
345 dataset = g_dataset_lookup (dataset_location);
348 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
349 dataset->location = dataset_location;
350 g_datalist_init (&dataset->datalist);
351 g_hash_table_insert (g_dataset_location_ht,
352 (gpointer) dataset->location,
356 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
357 G_UNLOCK (g_dataset_global);
361 g_datalist_id_set_data_full (GData **datalist,
364 GDestroyNotify destroy_func)
366 g_return_if_fail (datalist != NULL);
368 g_return_if_fail (destroy_func == NULL);
372 g_return_if_fail (key_id > 0);
377 G_LOCK (g_dataset_global);
378 if (!g_dataset_location_ht)
379 g_data_initialize ();
381 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
382 G_UNLOCK (g_dataset_global);
386 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
389 gpointer ret_data = NULL;
391 g_return_val_if_fail (dataset_location != NULL, NULL);
393 G_LOCK (g_dataset_global);
394 if (key_id && g_dataset_location_ht)
398 dataset = g_dataset_lookup (dataset_location);
400 ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
402 G_UNLOCK (g_dataset_global);
408 g_datalist_id_remove_no_notify (GData **datalist,
411 gpointer ret_data = NULL;
413 g_return_val_if_fail (datalist != NULL, NULL);
415 G_LOCK (g_dataset_global);
416 if (key_id && g_dataset_location_ht)
417 ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
418 G_UNLOCK (g_dataset_global);
424 g_dataset_id_get_data (gconstpointer dataset_location,
427 g_return_val_if_fail (dataset_location != NULL, NULL);
429 G_LOCK (g_dataset_global);
430 if (key_id && g_dataset_location_ht)
432 register GDataset *dataset;
434 dataset = g_dataset_lookup (dataset_location);
437 register GData *list;
439 for (list = dataset->datalist; list; list = list->next)
440 if (list->id == key_id)
442 G_UNLOCK (g_dataset_global);
447 G_UNLOCK (g_dataset_global);
453 g_datalist_id_get_data (GData **datalist,
456 g_return_val_if_fail (datalist != NULL, NULL);
460 register GData *list;
462 for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
463 if (list->id == key_id)
471 g_dataset_foreach (gconstpointer dataset_location,
472 GDataForeachFunc func,
475 register GDataset *dataset;
477 g_return_if_fail (dataset_location != NULL);
478 g_return_if_fail (func != NULL);
480 G_LOCK (g_dataset_global);
481 if (g_dataset_location_ht)
483 dataset = g_dataset_lookup (dataset_location);
484 G_UNLOCK (g_dataset_global);
487 register GData *list, *next;
489 for (list = dataset->datalist; list; list = next)
492 func (list->id, list->data, user_data);
498 G_UNLOCK (g_dataset_global);
503 g_datalist_foreach (GData **datalist,
504 GDataForeachFunc func,
507 register GData *list, *next;
509 g_return_if_fail (datalist != NULL);
510 g_return_if_fail (func != NULL);
512 for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
515 func (list->id, list->data, user_data);
520 g_datalist_init (GData **datalist)
522 g_return_if_fail (datalist != NULL);
528 * g_datalist_set_flags:
529 * @datalist: pointer to the location that holds a list
530 * @flags: the flags to turn on. The values of the flags are
531 * restricted by %G_DATALIST_FLAGS_MASK (currently
532 * 3; giving two possible boolean flags).
533 * A value for @flags that doesn't fit within the mask is
536 * Turns on flag values for a data list. This function is used
537 * to keep a small number of boolean flags in an object with
538 * a data list without using any additional space. It is
539 * not generally useful except in circumstances where space
540 * is very tight. (It is used in the base #GObject type, for
544 g_datalist_set_flags (GData **datalist,
547 g_return_if_fail (datalist != NULL);
548 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
550 G_DATALIST_SET_FLAGS (datalist, flags);
554 * g_datalist_unset_flags:
555 * @datalist: pointer to the location that holds a list
556 * @flags: the flags to turn off. The values of the flags are
557 * restricted by %G_DATALIST_FLAGS_MASK (currently
558 * 3: giving two possible boolean flags).
559 * A value for @flags that doesn't fit within the mask is
562 * Turns off flag values for a data list. See g_datalist_unset_flags()
565 g_datalist_unset_flags (GData **datalist,
568 g_return_if_fail (datalist != NULL);
569 g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
571 G_DATALIST_UNSET_FLAGS (datalist, 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
584 g_datalist_get_flags (GData **datalist)
586 g_return_val_if_fail (datalist != NULL, 0);
588 return G_DATALIST_GET_FLAGS (datalist);
591 /* HOLDS: g_dataset_global_lock */
593 g_data_initialize (void)
595 g_return_if_fail (g_dataset_location_ht == NULL);
597 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
598 g_dataset_cached = NULL;
599 g_dataset_mem_chunk =
600 g_mem_chunk_new ("GDataset MemChunk",
602 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
605 g_mem_chunk_new ("GData MemChunk",
607 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
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);
626 g_quark_from_string (const gchar *string)
630 g_return_val_if_fail (string != NULL, 0);
632 G_LOCK (g_quark_global);
634 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
637 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
642 quark = g_quark_new (g_strdup (string));
643 G_UNLOCK (g_quark_global);
649 g_quark_from_static_string (const gchar *string)
653 g_return_val_if_fail (string != NULL, 0);
655 G_LOCK (g_quark_global);
657 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
660 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
665 quark = g_quark_new ((gchar*) string);
666 G_UNLOCK (g_quark_global);
671 G_CONST_RETURN gchar*
672 g_quark_to_string (GQuark quark)
674 gchar* result = NULL;
675 G_LOCK (g_quark_global);
676 if (quark > 0 && quark <= g_quark_seq_id)
677 result = g_quarks[quark - 1];
678 G_UNLOCK (g_quark_global);
683 /* HOLDS: g_quark_global_lock */
685 g_quark_new (gchar *string)
689 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
690 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
692 g_quarks[g_quark_seq_id] = string;
694 quark = g_quark_seq_id;
695 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
700 #define __G_DATASET_C__
701 #include "galiasdef.c"