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
203 if (list->destroy_func)
204 list->destroy_func (list->data);
206 if (g_data_cache_length < G_DATA_CACHE_MAX)
208 list->next = g_data_cache;
210 g_data_cache_length++;
213 g_mem_chunk_free (g_data_mem_chunk, list);
226 if (list->id == key_id)
228 if (!list->destroy_func)
231 list->destroy_func = destroy_func;
235 register GDestroyNotify dfunc;
236 register gpointer ddata;
238 dfunc = list->destroy_func;
241 list->destroy_func = destroy_func;
243 /* we need to have updated all structures prior to
244 * invokation of the destroy function
258 g_data_cache = list->next;
259 g_data_cache_length--;
262 list = g_chunk_new (GData, g_data_mem_chunk);
263 list->next = *datalist;
266 list->destroy_func = destroy_func;
272 g_dataset_id_set_data_full (gconstpointer dataset_location,
275 GDestroyNotify destroy_func)
277 register GDataset *dataset;
279 g_return_if_fail (dataset_location != NULL);
283 g_return_if_fail (key_id > 0);
288 if (!g_dataset_location_ht)
289 g_data_initialize ();
291 dataset = g_dataset_lookup (dataset_location);
294 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
295 dataset->location = dataset_location;
296 g_datalist_init (&dataset->datalist);
297 g_hash_table_insert (g_dataset_location_ht,
298 (gpointer) dataset->location,
302 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
306 g_datalist_id_set_data_full (GData **datalist,
309 GDestroyNotify destroy_func)
311 g_return_if_fail (datalist != NULL);
315 g_return_if_fail (key_id > 0);
320 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
324 g_dataset_id_set_destroy (gconstpointer dataset_location,
326 GDestroyNotify destroy_func)
328 register GDataset *dataset;
330 g_return_if_fail (dataset_location != NULL);
331 g_return_if_fail (key_id > 0);
333 if (g_dataset_location_ht)
335 dataset = g_dataset_lookup (dataset_location);
338 register GData *list;
340 for (list = dataset->datalist; list; list = list->next)
341 if (list->id == key_id)
343 list->destroy_func = destroy_func;
351 g_datalist_id_set_destroy (GData **datalist,
353 GDestroyNotify destroy_func)
355 register GData *list;
357 g_return_if_fail (datalist != NULL);
358 g_return_if_fail (key_id > 0);
360 for (list = *datalist; list; list = list->next)
361 if (list->id == key_id)
363 list->destroy_func = destroy_func;
369 g_dataset_id_get_data (gconstpointer dataset_location,
372 g_return_val_if_fail (dataset_location != NULL, NULL);
374 if (key_id && g_dataset_location_ht)
376 register GDataset *dataset;
378 dataset = g_dataset_lookup (dataset_location);
381 register GData *list;
383 for (list = dataset->datalist; list; list = list->next)
384 if (list->id == key_id)
393 g_datalist_id_get_data (GData **datalist,
396 g_return_val_if_fail (datalist != NULL, NULL);
400 register GData *list;
402 for (list = *datalist; list; list = list->next)
403 if (list->id == key_id)
411 g_dataset_foreach (gconstpointer dataset_location,
412 GDataForeachFunc func,
415 register GDataset *dataset;
417 g_return_if_fail (dataset_location != NULL);
418 g_return_if_fail (func != NULL);
420 dataset = g_dataset_lookup (dataset_location);
423 register GData *list;
425 for (list = dataset->datalist; list; list = list->next)
426 func (list->id, list->data, user_data);
431 g_datalist_foreach (GData **datalist,
432 GDataForeachFunc func,
435 register GData *list;
437 g_return_if_fail (datalist != NULL);
438 g_return_if_fail (func != NULL);
440 for (list = *datalist; list; list = list->next)
441 func (list->id, list->data, user_data);
445 g_datalist_init (GData **datalist)
447 g_return_if_fail (datalist != NULL);
453 g_data_initialize (void)
455 if (!g_dataset_location_ht)
457 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
458 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
459 g_dataset_cached = NULL;
460 g_dataset_mem_chunk =
461 g_mem_chunk_new ("GDataset MemChunk",
463 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
466 g_mem_chunk_new ("GData MemChunk",
468 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
474 g_quark_try_string (const gchar *string)
476 g_return_val_if_fail (string != NULL, 0);
479 return (gulong) g_hash_table_lookup (g_quark_ht, string);
485 g_quark_from_string (const gchar *string)
489 g_return_val_if_fail (string != NULL, 0);
492 g_data_initialize ();
494 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
496 quark = g_quark_new (g_strdup (string));
502 g_quark_from_static_string (const gchar *string)
506 g_return_val_if_fail (string != NULL, 0);
509 g_data_initialize ();
511 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
513 quark = g_quark_new (string);
519 g_quark_to_string (GQuark quark)
521 if (quark > 0 && quark <= g_quark_seq_id)
522 return g_quarks[quark - 1];
528 g_quark_new (const gchar *string)
532 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
533 g_quarks = g_realloc (g_quarks,
534 (g_quark_seq_id + G_QUARK_BLOCK_SIZE) * sizeof (gchar*));
537 g_quarks[g_quark_seq_id] = (gchar*) string;
539 quark = g_quark_seq_id;
540 g_hash_table_insert (g_quark_ht, (gchar*) string, GUINT_TO_POINTER (quark));