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.
27 #define G_QUARK_BLOCK_SIZE (512)
28 #define G_DATA_MEM_CHUNK_PREALLOC (128)
29 #define G_DATA_CACHE_MAX (512)
30 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
33 /* --- structures --- */
34 typedef struct _GDataset GDataset;
40 GDestroyNotify destroy_func;
45 gconstpointer location;
50 /* --- prototypes --- */
51 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
52 static inline void g_datalist_clear_i (GData **datalist);
53 static void g_dataset_destroy_internal (GDataset *dataset);
54 static inline void g_data_set_internal (GData **datalist,
57 GDestroyNotify destroy_func,
59 static void g_data_initialize (void);
60 static inline GQuark g_quark_new (const gchar *string);
63 /* --- variables --- */
64 static GHashTable *g_quark_ht = NULL;
65 static gchar **g_quarks = NULL;
66 static GQuark g_quark_seq_id = 0;
67 static GHashTable *g_dataset_location_ht = NULL;
68 static GDataset *g_dataset_cached = NULL;
69 static GMemChunk *g_dataset_mem_chunk = NULL;
70 static GMemChunk *g_data_mem_chunk = NULL;
71 static GData *g_data_cache = NULL;
72 static guint g_data_cache_length = 0;
75 /* --- functions --- */
77 g_datalist_clear_i (GData **datalist)
81 /* unlink *all* items before walking their destructors
93 if (prev->destroy_func)
94 prev->destroy_func (prev->data);
96 if (g_data_cache_length < G_DATA_CACHE_MAX)
98 prev->next = g_data_cache;
100 g_data_cache_length++;
103 g_mem_chunk_free (g_data_mem_chunk, prev);
108 g_datalist_clear (GData **datalist)
110 g_return_if_fail (datalist != NULL);
113 g_datalist_clear_i (datalist);
116 static inline GDataset*
117 g_dataset_lookup (gconstpointer dataset_location)
119 register GDataset *dataset;
121 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
122 return g_dataset_cached;
124 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
126 g_dataset_cached = dataset;
132 g_dataset_destroy_internal (GDataset *dataset)
134 register gconstpointer dataset_location;
136 dataset_location = dataset->location;
139 if (!dataset->datalist)
141 if (dataset == g_dataset_cached)
142 g_dataset_cached = NULL;
143 g_hash_table_remove (g_dataset_location_ht, dataset_location);
144 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
148 g_datalist_clear_i (&dataset->datalist);
149 dataset = g_dataset_lookup (dataset_location);
154 g_dataset_destroy (gconstpointer dataset_location)
156 g_return_if_fail (dataset_location != NULL);
158 if (g_dataset_location_ht)
160 register GDataset *dataset;
162 dataset = g_dataset_lookup (dataset_location);
164 g_dataset_destroy_internal (dataset);
169 g_data_set_internal (GData **datalist,
172 GDestroyNotify destroy_func,
175 register GData *list;
180 register GData *prev;
185 if (list->id == key_id)
188 prev->next = list->next;
191 *datalist = list->next;
193 /* the dataset destruction *must* be done
194 * prior to invokation of the data destroy function
196 if (!*datalist && dataset)
197 g_dataset_destroy_internal (dataset);
200 /* the GData struct *must* already be unlinked
201 * when invoking the destroy function
202 * we use (data==NULL && destroy_func!=NULL) as
203 * a special hint combination to "steal"
204 * data without destroy notification
206 if (list->destroy_func && !destroy_func)
207 list->destroy_func (list->data);
209 if (g_data_cache_length < G_DATA_CACHE_MAX)
211 list->next = g_data_cache;
213 g_data_cache_length++;
216 g_mem_chunk_free (g_data_mem_chunk, list);
229 if (list->id == key_id)
231 if (!list->destroy_func)
234 list->destroy_func = destroy_func;
238 register GDestroyNotify dfunc;
239 register gpointer ddata;
241 dfunc = list->destroy_func;
244 list->destroy_func = destroy_func;
246 /* we need to have updated all structures prior to
247 * invokation of the destroy function
261 g_data_cache = list->next;
262 g_data_cache_length--;
265 list = g_chunk_new (GData, g_data_mem_chunk);
266 list->next = *datalist;
269 list->destroy_func = destroy_func;
275 g_dataset_id_set_data_full (gconstpointer dataset_location,
278 GDestroyNotify destroy_func)
280 register GDataset *dataset;
282 g_return_if_fail (dataset_location != NULL);
284 g_return_if_fail (destroy_func == NULL);
288 g_return_if_fail (key_id > 0);
293 if (!g_dataset_location_ht)
294 g_data_initialize ();
296 dataset = g_dataset_lookup (dataset_location);
299 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
300 dataset->location = dataset_location;
301 g_datalist_init (&dataset->datalist);
302 g_hash_table_insert (g_dataset_location_ht,
303 (gpointer) dataset->location,
307 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
311 g_datalist_id_set_data_full (GData **datalist,
314 GDestroyNotify destroy_func)
316 g_return_if_fail (datalist != NULL);
318 g_return_if_fail (destroy_func == NULL);
322 g_return_if_fail (key_id > 0);
327 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
331 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
334 g_return_if_fail (dataset_location != NULL);
336 if (key_id && g_dataset_location_ht)
340 dataset = g_dataset_lookup (dataset_location);
342 g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
347 g_datalist_id_remove_no_notify (GData **datalist,
350 g_return_if_fail (datalist != NULL);
353 g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
357 g_dataset_id_get_data (gconstpointer dataset_location,
360 g_return_val_if_fail (dataset_location != NULL, NULL);
362 if (key_id && g_dataset_location_ht)
364 register GDataset *dataset;
366 dataset = g_dataset_lookup (dataset_location);
369 register GData *list;
371 for (list = dataset->datalist; list; list = list->next)
372 if (list->id == key_id)
381 g_datalist_id_get_data (GData **datalist,
384 g_return_val_if_fail (datalist != NULL, NULL);
388 register GData *list;
390 for (list = *datalist; list; list = list->next)
391 if (list->id == key_id)
399 g_dataset_foreach (gconstpointer dataset_location,
400 GDataForeachFunc func,
403 register GDataset *dataset;
405 g_return_if_fail (dataset_location != NULL);
406 g_return_if_fail (func != NULL);
408 dataset = g_dataset_lookup (dataset_location);
411 register GData *list;
413 for (list = dataset->datalist; list; list = list->next)
414 func (list->id, list->data, user_data);
419 g_datalist_foreach (GData **datalist,
420 GDataForeachFunc func,
423 register GData *list;
425 g_return_if_fail (datalist != NULL);
426 g_return_if_fail (func != NULL);
428 for (list = *datalist; list; list = list->next)
429 func (list->id, list->data, user_data);
433 g_datalist_init (GData **datalist)
435 g_return_if_fail (datalist != NULL);
441 g_data_initialize (void)
443 if (!g_dataset_location_ht)
445 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
446 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
447 g_dataset_cached = NULL;
448 g_dataset_mem_chunk =
449 g_mem_chunk_new ("GDataset MemChunk",
451 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
454 g_mem_chunk_new ("GData MemChunk",
456 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
462 g_quark_try_string (const gchar *string)
464 g_return_val_if_fail (string != NULL, 0);
467 return (gulong) g_hash_table_lookup (g_quark_ht, string);
473 g_quark_from_string (const gchar *string)
477 g_return_val_if_fail (string != NULL, 0);
480 g_data_initialize ();
482 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
484 quark = g_quark_new (g_strdup (string));
490 g_quark_from_static_string (const gchar *string)
494 g_return_val_if_fail (string != NULL, 0);
497 g_data_initialize ();
499 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
501 quark = g_quark_new (string);
507 g_quark_to_string (GQuark quark)
509 if (quark > 0 && quark <= g_quark_seq_id)
510 return g_quarks[quark - 1];
516 g_quark_new (const gchar *string)
520 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
521 g_quarks = g_realloc (g_quarks,
522 (g_quark_seq_id + G_QUARK_BLOCK_SIZE) * sizeof (gchar*));
525 g_quarks[g_quark_seq_id] = (gchar*) string;
527 quark = g_quark_seq_id;
528 g_hash_table_insert (g_quark_ht, (gchar*) string, GUINT_TO_POINTER (quark));