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;
177 if (!g_dataset_location_ht)
178 g_data_initialize ();
183 register GData *prev;
188 if (list->id == key_id)
191 prev->next = list->next;
194 *datalist = list->next;
196 /* the dataset destruction *must* be done
197 * prior to invokation of the data destroy function
199 if (!*datalist && dataset)
200 g_dataset_destroy_internal (dataset);
203 /* the GData struct *must* already be unlinked
204 * when invoking the destroy function
205 * we use (data==NULL && destroy_func!=NULL) as
206 * a special hint combination to "steal"
207 * data without destroy notification
209 if (list->destroy_func && !destroy_func)
210 list->destroy_func (list->data);
212 if (g_data_cache_length < G_DATA_CACHE_MAX)
214 list->next = g_data_cache;
216 g_data_cache_length++;
219 g_mem_chunk_free (g_data_mem_chunk, list);
232 if (list->id == key_id)
234 if (!list->destroy_func)
237 list->destroy_func = destroy_func;
241 register GDestroyNotify dfunc;
242 register gpointer ddata;
244 dfunc = list->destroy_func;
247 list->destroy_func = destroy_func;
249 /* we need to have updated all structures prior to
250 * invokation of the destroy function
264 g_data_cache = list->next;
265 g_data_cache_length--;
268 list = g_chunk_new (GData, g_data_mem_chunk);
269 list->next = *datalist;
272 list->destroy_func = destroy_func;
278 g_dataset_id_set_data_full (gconstpointer dataset_location,
281 GDestroyNotify destroy_func)
283 register GDataset *dataset;
285 g_return_if_fail (dataset_location != NULL);
287 g_return_if_fail (destroy_func == NULL);
291 g_return_if_fail (key_id > 0);
296 if (!g_dataset_location_ht)
297 g_data_initialize ();
299 dataset = g_dataset_lookup (dataset_location);
302 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
303 dataset->location = dataset_location;
304 g_datalist_init (&dataset->datalist);
305 g_hash_table_insert (g_dataset_location_ht,
306 (gpointer) dataset->location,
310 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
314 g_datalist_id_set_data_full (GData **datalist,
317 GDestroyNotify destroy_func)
319 g_return_if_fail (datalist != NULL);
321 g_return_if_fail (destroy_func == NULL);
325 g_return_if_fail (key_id > 0);
330 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
334 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
337 g_return_if_fail (dataset_location != NULL);
339 if (key_id && g_dataset_location_ht)
343 dataset = g_dataset_lookup (dataset_location);
345 g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
350 g_datalist_id_remove_no_notify (GData **datalist,
353 g_return_if_fail (datalist != NULL);
356 g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
360 g_dataset_id_get_data (gconstpointer dataset_location,
363 g_return_val_if_fail (dataset_location != NULL, NULL);
365 if (key_id && g_dataset_location_ht)
367 register GDataset *dataset;
369 dataset = g_dataset_lookup (dataset_location);
372 register GData *list;
374 for (list = dataset->datalist; list; list = list->next)
375 if (list->id == key_id)
384 g_datalist_id_get_data (GData **datalist,
387 g_return_val_if_fail (datalist != NULL, NULL);
391 register GData *list;
393 for (list = *datalist; list; list = list->next)
394 if (list->id == key_id)
402 g_dataset_foreach (gconstpointer dataset_location,
403 GDataForeachFunc func,
406 register GDataset *dataset;
408 g_return_if_fail (dataset_location != NULL);
409 g_return_if_fail (func != NULL);
411 dataset = g_dataset_lookup (dataset_location);
414 register GData *list;
416 for (list = dataset->datalist; list; list = list->next)
417 func (list->id, list->data, user_data);
422 g_datalist_foreach (GData **datalist,
423 GDataForeachFunc func,
426 register GData *list;
428 g_return_if_fail (datalist != NULL);
429 g_return_if_fail (func != NULL);
431 for (list = *datalist; list; list = list->next)
432 func (list->id, list->data, user_data);
436 g_datalist_init (GData **datalist)
438 g_return_if_fail (datalist != NULL);
444 g_data_initialize (void)
446 if (!g_dataset_location_ht)
448 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
449 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
450 g_dataset_cached = NULL;
451 g_dataset_mem_chunk =
452 g_mem_chunk_new ("GDataset MemChunk",
454 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
457 g_mem_chunk_new ("GData MemChunk",
459 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
465 g_quark_try_string (const gchar *string)
467 g_return_val_if_fail (string != NULL, 0);
470 return (gulong) g_hash_table_lookup (g_quark_ht, string);
476 g_quark_from_string (const gchar *string)
480 g_return_val_if_fail (string != NULL, 0);
483 g_data_initialize ();
485 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
487 quark = g_quark_new (g_strdup (string));
493 g_quark_from_static_string (const gchar *string)
497 g_return_val_if_fail (string != NULL, 0);
500 g_data_initialize ();
502 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
504 quark = g_quark_new (string);
510 g_quark_to_string (GQuark quark)
512 if (quark > 0 && quark <= g_quark_seq_id)
513 return g_quarks[quark - 1];
519 g_quark_new (const gchar *string)
523 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
524 g_quarks = g_realloc (g_quarks,
525 (g_quark_seq_id + G_QUARK_BLOCK_SIZE) * sizeof (gchar*));
528 g_quarks[g_quark_seq_id] = (gchar*) string;
530 quark = g_quark_seq_id;
531 g_hash_table_insert (g_quark_ht, (gchar*) string, GUINT_TO_POINTER (quark));