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 * Modified by the GLib Team and others 1997-1999. 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 #define G_QUARK_BLOCK_SIZE (512)
41 #define G_DATA_MEM_CHUNK_PREALLOC (128)
42 #define G_DATA_CACHE_MAX (512)
43 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
46 /* --- structures --- */
47 typedef struct _GDataset GDataset;
53 GDestroyNotify destroy_func;
58 gconstpointer location;
63 /* --- prototypes --- */
64 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
65 static inline void g_datalist_clear_i (GData **datalist);
66 static void g_dataset_destroy_internal (GDataset *dataset);
67 static inline void g_data_set_internal (GData **datalist,
70 GDestroyNotify destroy_func,
72 static void g_data_initialize (void);
73 static inline GQuark g_quark_new (gchar *string);
76 /* --- variables --- */
77 G_LOCK_DEFINE_STATIC (g_dataset_global);
78 static GHashTable *g_dataset_location_ht = NULL;
79 static GDataset *g_dataset_cached = NULL; /* should this be
81 static GMemChunk *g_dataset_mem_chunk = NULL;
82 static GMemChunk *g_data_mem_chunk = NULL;
83 static GData *g_data_cache = NULL;
84 static guint g_data_cache_length = 0;
86 G_LOCK_DEFINE_STATIC (g_quark_global);
87 static GHashTable *g_quark_ht = NULL;
88 static gchar **g_quarks = NULL;
89 static GQuark g_quark_seq_id = 0;
92 /* --- functions --- */
94 /* HOLDS: g_dataset_global_lock */
96 g_datalist_clear_i (GData **datalist)
100 /* unlink *all* items before walking their destructors
107 register GData *prev;
112 if (prev->destroy_func)
113 prev->destroy_func (prev->data);
115 if (g_data_cache_length < G_DATA_CACHE_MAX)
117 prev->next = g_data_cache;
119 g_data_cache_length++;
122 g_mem_chunk_free (g_data_mem_chunk, prev);
127 g_datalist_clear (GData **datalist)
129 g_return_if_fail (datalist != NULL);
131 G_LOCK (g_dataset_global);
132 if (!g_dataset_location_ht)
133 g_data_initialize ();
136 g_datalist_clear_i (datalist);
137 G_UNLOCK (g_dataset_global);
140 /* HOLDS: g_dataset_global_lock */
141 static inline GDataset*
142 g_dataset_lookup (gconstpointer dataset_location)
144 register GDataset *dataset;
146 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
147 return g_dataset_cached;
149 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
151 g_dataset_cached = dataset;
156 /* HOLDS: g_dataset_global_lock */
158 g_dataset_destroy_internal (GDataset *dataset)
160 register gconstpointer dataset_location;
162 dataset_location = dataset->location;
165 if (!dataset->datalist)
167 if (dataset == g_dataset_cached)
168 g_dataset_cached = NULL;
169 g_hash_table_remove (g_dataset_location_ht, dataset_location);
170 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
174 g_datalist_clear_i (&dataset->datalist);
175 dataset = g_dataset_lookup (dataset_location);
180 g_dataset_destroy (gconstpointer dataset_location)
182 g_return_if_fail (dataset_location != NULL);
184 G_LOCK (g_dataset_global);
185 if (g_dataset_location_ht)
187 register GDataset *dataset;
189 dataset = g_dataset_lookup (dataset_location);
191 g_dataset_destroy_internal (dataset);
193 G_UNLOCK (g_dataset_global);
196 /* HOLDS: g_dataset_global_lock */
198 g_data_set_internal (GData **datalist,
201 GDestroyNotify destroy_func,
204 register GData *list;
209 register GData *prev;
214 if (list->id == key_id)
217 prev->next = list->next;
220 *datalist = list->next;
222 /* the dataset destruction *must* be done
223 * prior to invokation of the data destroy function
225 if (!*datalist && dataset)
226 g_dataset_destroy_internal (dataset);
229 /* the GData struct *must* already be unlinked
230 * when invoking the destroy function.
231 * we use (data==NULL && destroy_func!=NULL) as
232 * a special hint combination to "steal"
233 * data without destroy notification
235 if (list->destroy_func && !destroy_func)
236 list->destroy_func (list->data);
238 if (g_data_cache_length < G_DATA_CACHE_MAX)
240 list->next = g_data_cache;
242 g_data_cache_length++;
245 g_mem_chunk_free (g_data_mem_chunk, list);
258 if (list->id == key_id)
260 if (!list->destroy_func)
263 list->destroy_func = destroy_func;
267 register GDestroyNotify dfunc;
268 register gpointer ddata;
270 dfunc = list->destroy_func;
273 list->destroy_func = destroy_func;
275 /* we need to have updated all structures prior to
276 * invokation of the destroy function
290 g_data_cache = list->next;
291 g_data_cache_length--;
294 list = g_chunk_new (GData, g_data_mem_chunk);
295 list->next = *datalist;
298 list->destroy_func = destroy_func;
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_chunk_new (GDataset, g_dataset_mem_chunk);
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 g_return_if_fail (dataset_location != NULL);
372 G_LOCK (g_dataset_global);
373 if (key_id && g_dataset_location_ht)
377 dataset = g_dataset_lookup (dataset_location);
379 g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
381 G_UNLOCK (g_dataset_global);
385 g_datalist_id_remove_no_notify (GData **datalist,
388 g_return_if_fail (datalist != NULL);
390 G_LOCK (g_dataset_global);
391 if (key_id && g_dataset_location_ht)
392 g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
393 G_UNLOCK (g_dataset_global);
397 g_dataset_id_get_data (gconstpointer dataset_location,
400 g_return_val_if_fail (dataset_location != NULL, NULL);
402 G_LOCK (g_dataset_global);
403 if (key_id && g_dataset_location_ht)
405 register GDataset *dataset;
407 dataset = g_dataset_lookup (dataset_location);
410 register GData *list;
412 for (list = dataset->datalist; list; list = list->next)
413 if (list->id == key_id)
415 G_UNLOCK (g_dataset_global);
420 G_UNLOCK (g_dataset_global);
426 g_datalist_id_get_data (GData **datalist,
429 g_return_val_if_fail (datalist != NULL, NULL);
433 register GData *list;
435 for (list = *datalist; list; list = list->next)
436 if (list->id == key_id)
444 g_dataset_foreach (gconstpointer dataset_location,
445 GDataForeachFunc func,
448 register GDataset *dataset;
450 g_return_if_fail (dataset_location != NULL);
451 g_return_if_fail (func != NULL);
453 G_LOCK (g_dataset_global);
454 if (g_dataset_location_ht)
456 dataset = g_dataset_lookup (dataset_location);
457 G_UNLOCK (g_dataset_global);
460 register GData *list;
462 for (list = dataset->datalist; list; list = list->next)
463 func (list->id, list->data, user_data);
468 G_UNLOCK (g_dataset_global);
473 g_datalist_foreach (GData **datalist,
474 GDataForeachFunc func,
477 register GData *list;
479 g_return_if_fail (datalist != NULL);
480 g_return_if_fail (func != NULL);
482 for (list = *datalist; list; list = list->next)
483 func (list->id, list->data, user_data);
487 g_datalist_init (GData **datalist)
489 g_return_if_fail (datalist != NULL);
494 /* HOLDS: g_dataset_global_lock */
496 g_data_initialize (void)
498 g_return_if_fail (g_dataset_location_ht == NULL);
500 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
501 g_dataset_cached = NULL;
502 g_dataset_mem_chunk =
503 g_mem_chunk_new ("GDataset MemChunk",
505 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
508 g_mem_chunk_new ("GData MemChunk",
510 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
515 g_quark_try_string (const gchar *string)
518 g_return_val_if_fail (string != NULL, 0);
520 G_LOCK (g_quark_global);
522 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
523 G_UNLOCK (g_quark_global);
529 g_quark_from_string (const gchar *string)
533 g_return_val_if_fail (string != NULL, 0);
535 G_LOCK (g_quark_global);
537 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
540 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
545 quark = g_quark_new (g_strdup (string));
546 G_UNLOCK (g_quark_global);
552 g_quark_from_static_string (const gchar *string)
556 g_return_val_if_fail (string != NULL, 0);
558 G_LOCK (g_quark_global);
560 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
563 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
568 quark = g_quark_new ((gchar*) string);
569 G_UNLOCK (g_quark_global);
575 g_quark_to_string (GQuark quark)
577 gchar* result = NULL;
578 G_LOCK (g_quark_global);
579 if (quark > 0 && quark <= g_quark_seq_id)
580 result = g_quarks[quark - 1];
581 G_UNLOCK (g_quark_global);
586 /* HOLDS: g_quark_global_lock */
588 g_quark_new (gchar *string)
592 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
593 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
595 g_quarks[g_quark_seq_id] = string;
597 quark = g_quark_seq_id;
598 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));