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 Library 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 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library 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 * MT safe ; FIXME: might still freeze, watch out, not thoroughly
33 #define G_QUARK_BLOCK_SIZE (512)
34 #define G_DATA_MEM_CHUNK_PREALLOC (128)
35 #define G_DATA_CACHE_MAX (512)
36 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
39 /* --- structures --- */
40 typedef struct _GDataset GDataset;
46 GDestroyNotify destroy_func;
51 gconstpointer location;
56 /* --- prototypes --- */
57 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
58 static inline void g_datalist_clear_i (GData **datalist);
59 static void g_dataset_destroy_internal (GDataset *dataset);
60 static inline void g_data_set_internal (GData **datalist,
63 GDestroyNotify destroy_func,
65 static void g_data_initialize (void);
66 static inline GQuark g_quark_new (gchar *string);
69 /* --- variables --- */
70 G_LOCK_DECLARE_STATIC (g_dataset_global);
71 static GHashTable *g_dataset_location_ht = NULL;
72 static GDataset *g_dataset_cached = NULL; /* should this be
74 static GMemChunk *g_dataset_mem_chunk = NULL;
75 static GMemChunk *g_data_mem_chunk = NULL;
76 static GData *g_data_cache = NULL;
77 static guint g_data_cache_length = 0;
79 G_LOCK_DECLARE_STATIC (g_quark_global);
80 static GHashTable *g_quark_ht = NULL;
81 static gchar **g_quarks = NULL;
82 static GQuark g_quark_seq_id = 0;
85 /* --- functions --- */
87 /* HOLDS: g_dataset_global_lock */
89 g_datalist_clear_i (GData **datalist)
93 /* unlink *all* items before walking their destructors
100 register GData *prev;
105 if (prev->destroy_func)
106 prev->destroy_func (prev->data);
108 if (g_data_cache_length < G_DATA_CACHE_MAX)
110 prev->next = g_data_cache;
112 g_data_cache_length++;
115 g_mem_chunk_free (g_data_mem_chunk, prev);
120 g_datalist_clear (GData **datalist)
122 g_return_if_fail (datalist != NULL);
124 G_LOCK (g_dataset_global);
125 if (!g_dataset_location_ht)
126 g_data_initialize ();
129 g_datalist_clear_i (datalist);
130 G_UNLOCK (g_dataset_global);
133 /* HOLDS: g_dataset_global_lock */
134 static inline GDataset*
135 g_dataset_lookup (gconstpointer dataset_location)
137 register GDataset *dataset;
139 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
140 return g_dataset_cached;
142 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
144 g_dataset_cached = dataset;
149 /* HOLDS: g_dataset_global_lock */
151 g_dataset_destroy_internal (GDataset *dataset)
153 register gconstpointer dataset_location;
155 dataset_location = dataset->location;
158 if (!dataset->datalist)
160 if (dataset == g_dataset_cached)
161 g_dataset_cached = NULL;
162 g_hash_table_remove (g_dataset_location_ht, dataset_location);
163 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
167 g_datalist_clear_i (&dataset->datalist);
168 dataset = g_dataset_lookup (dataset_location);
173 g_dataset_destroy (gconstpointer dataset_location)
175 g_return_if_fail (dataset_location != NULL);
177 G_LOCK (g_dataset_global);
178 if (g_dataset_location_ht)
180 register GDataset *dataset;
182 dataset = g_dataset_lookup (dataset_location);
184 g_dataset_destroy_internal (dataset);
186 G_UNLOCK (g_dataset_global);
189 /* HOLDS: g_dataset_global_lock */
191 g_data_set_internal (GData **datalist,
194 GDestroyNotify destroy_func,
197 register GData *list;
202 register GData *prev;
207 if (list->id == key_id)
210 prev->next = list->next;
213 *datalist = list->next;
215 /* the dataset destruction *must* be done
216 * prior to invokation of the data destroy function
218 if (!*datalist && dataset)
219 g_dataset_destroy_internal (dataset);
222 /* the GData struct *must* already be unlinked
223 * when invoking the destroy function.
224 * we use (data==NULL && destroy_func!=NULL) as
225 * a special hint combination to "steal"
226 * data without destroy notification
228 if (list->destroy_func && !destroy_func)
229 list->destroy_func (list->data);
231 if (g_data_cache_length < G_DATA_CACHE_MAX)
233 list->next = g_data_cache;
235 g_data_cache_length++;
238 g_mem_chunk_free (g_data_mem_chunk, list);
251 if (list->id == key_id)
253 if (!list->destroy_func)
256 list->destroy_func = destroy_func;
260 register GDestroyNotify dfunc;
261 register gpointer ddata;
263 dfunc = list->destroy_func;
266 list->destroy_func = destroy_func;
268 /* we need to have updated all structures prior to
269 * invokation of the destroy function
283 g_data_cache = list->next;
284 g_data_cache_length--;
287 list = g_chunk_new (GData, g_data_mem_chunk);
288 list->next = *datalist;
291 list->destroy_func = destroy_func;
297 g_dataset_id_set_data_full (gconstpointer dataset_location,
300 GDestroyNotify destroy_func)
302 register GDataset *dataset;
304 g_return_if_fail (dataset_location != NULL);
306 g_return_if_fail (destroy_func == NULL);
310 g_return_if_fail (key_id > 0);
315 G_LOCK (g_dataset_global);
316 if (!g_dataset_location_ht)
317 g_data_initialize ();
319 dataset = g_dataset_lookup (dataset_location);
322 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
323 dataset->location = dataset_location;
324 g_datalist_init (&dataset->datalist);
325 g_hash_table_insert (g_dataset_location_ht,
326 (gpointer) dataset->location,
330 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
331 G_UNLOCK (g_dataset_global);
335 g_datalist_id_set_data_full (GData **datalist,
338 GDestroyNotify destroy_func)
340 g_return_if_fail (datalist != NULL);
342 g_return_if_fail (destroy_func == NULL);
346 g_return_if_fail (key_id > 0);
351 G_LOCK (g_dataset_global);
352 if (!g_dataset_location_ht)
353 g_data_initialize ();
355 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
356 G_UNLOCK (g_dataset_global);
360 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
363 g_return_if_fail (dataset_location != NULL);
365 G_LOCK (g_dataset_global);
366 if (key_id && g_dataset_location_ht)
370 dataset = g_dataset_lookup (dataset_location);
372 g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
374 G_UNLOCK (g_dataset_global);
378 g_datalist_id_remove_no_notify (GData **datalist,
381 g_return_if_fail (datalist != NULL);
383 G_LOCK (g_dataset_global);
384 if (key_id && g_dataset_location_ht)
385 g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
386 G_UNLOCK (g_dataset_global);
390 g_dataset_id_get_data (gconstpointer dataset_location,
393 g_return_val_if_fail (dataset_location != NULL, NULL);
395 G_LOCK (g_dataset_global);
396 if (key_id && g_dataset_location_ht)
398 register GDataset *dataset;
400 dataset = g_dataset_lookup (dataset_location);
403 register GData *list;
405 for (list = dataset->datalist; list; list = list->next)
406 if (list->id == key_id)
408 G_UNLOCK (g_dataset_global);
413 G_UNLOCK (g_dataset_global);
419 g_datalist_id_get_data (GData **datalist,
422 g_return_val_if_fail (datalist != NULL, NULL);
426 register GData *list;
428 for (list = *datalist; list; list = list->next)
429 if (list->id == key_id)
437 g_dataset_foreach (gconstpointer dataset_location,
438 GDataForeachFunc func,
441 register GDataset *dataset;
443 g_return_if_fail (dataset_location != NULL);
444 g_return_if_fail (func != NULL);
446 G_LOCK (g_dataset_global);
447 if (g_dataset_location_ht)
449 dataset = g_dataset_lookup (dataset_location);
450 G_UNLOCK (g_dataset_global);
453 register GData *list;
455 for (list = dataset->datalist; list; list = list->next)
456 func (list->id, list->data, user_data);
461 G_UNLOCK (g_dataset_global);
466 g_datalist_foreach (GData **datalist,
467 GDataForeachFunc func,
470 register GData *list;
472 g_return_if_fail (datalist != NULL);
473 g_return_if_fail (func != NULL);
475 for (list = *datalist; list; list = list->next)
476 func (list->id, list->data, user_data);
480 g_datalist_init (GData **datalist)
482 g_return_if_fail (datalist != NULL);
487 /* HOLDS: g_dataset_global_lock */
489 g_data_initialize (void)
491 g_return_if_fail (g_dataset_location_ht == NULL);
493 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
494 g_dataset_cached = NULL;
495 g_dataset_mem_chunk =
496 g_mem_chunk_new ("GDataset MemChunk",
498 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
501 g_mem_chunk_new ("GData MemChunk",
503 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
508 g_quark_try_string (const gchar *string)
511 g_return_val_if_fail (string != NULL, 0);
513 G_LOCK (g_quark_global);
515 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
516 G_UNLOCK (g_quark_global);
522 g_quark_from_string (const gchar *string)
526 g_return_val_if_fail (string != NULL, 0);
528 G_LOCK (g_quark_global);
530 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
533 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
538 quark = g_quark_new (g_strdup (string));
539 G_UNLOCK (g_quark_global);
545 g_quark_from_static_string (const gchar *string)
549 g_return_val_if_fail (string != NULL, 0);
551 G_LOCK (g_quark_global);
553 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
556 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
561 quark = g_quark_new ((gchar*) string);
562 G_UNLOCK (g_quark_global);
568 g_quark_to_string (GQuark quark)
570 gchar* result = NULL;
571 G_LOCK (g_quark_global);
572 if (quark > 0 && quark <= g_quark_seq_id)
573 result = g_quarks[quark - 1];
574 G_UNLOCK (g_quark_global);
579 /* HOLDS: g_quark_global_lock */
581 g_quark_new (gchar *string)
585 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
586 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
588 g_quarks[g_quark_seq_id] = string;
590 quark = g_quark_seq_id;
591 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));