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 _GData GData;
35 typedef struct _GDataset GDataset;
41 GDestroyNotify destroy_func;
46 gconstpointer location;
51 /* --- prototypes --- */
52 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
53 static inline void g_datalist_clear_i (gpointer *datalist);
54 static void g_dataset_destroy_internal (GDataset *dataset);
55 static inline void g_data_set_internal (gpointer *datalist,
58 GDestroyNotify destroy_func,
60 static void g_data_initialize (void);
61 static inline GQuark g_quark_new (const gchar *string);
64 /* --- variables --- */
65 static GHashTable *g_quark_ht = NULL;
66 static gchar **g_quarks = NULL;
67 static GQuark g_quark_seq_id = 0;
68 static GHashTable *g_dataset_location_ht = NULL;
69 static GDataset *g_dataset_cached = NULL;
70 static GMemChunk *g_dataset_mem_chunk = NULL;
71 static GMemChunk *g_data_mem_chunk = NULL;
72 static GData *g_data_cache = NULL;
73 static guint g_data_cache_length = 0;
76 /* --- functions --- */
78 g_datalist_clear_i (gpointer *datalist)
82 /* unlink *all* items before walking their destructors
94 if (prev->destroy_func)
95 prev->destroy_func (prev->data);
97 if (g_data_cache_length < G_DATA_CACHE_MAX)
99 prev->next = g_data_cache;
101 g_data_cache_length++;
104 g_mem_chunk_free (g_data_mem_chunk, prev);
109 g_datalist_clear (gpointer *datalist)
111 g_return_if_fail (datalist != NULL);
114 g_datalist_clear_i (datalist);
117 static inline GDataset*
118 g_dataset_lookup (gconstpointer dataset_location)
120 register GDataset *dataset;
122 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
123 return g_dataset_cached;
125 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
127 g_dataset_cached = dataset;
133 g_dataset_destroy_internal (GDataset *dataset)
137 if (dataset == g_dataset_cached)
138 g_dataset_cached = NULL;
139 g_hash_table_remove (g_dataset_location_ht, dataset->location);
141 datalist = dataset->datalist;
142 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
144 g_datalist_clear_i (&datalist);
148 g_dataset_destroy (gconstpointer dataset_location)
150 register GDataset *dataset;
152 g_return_if_fail (dataset_location != NULL);
154 if (g_dataset_location_ht)
156 dataset = g_dataset_lookup (dataset_location);
158 g_dataset_destroy_internal (dataset);
163 g_data_set_internal (gpointer *datalist,
166 GDestroyNotify destroy_func,
169 register GData *list;
174 register GData *prev;
179 if (list->id == key_id)
182 prev->next = list->next;
185 *datalist = list->next;
187 /* the dataset destruction *must* be done
188 * prior to invokation of the data destroy function
190 if (!*datalist && d_dataset)
191 g_dataset_destroy_internal (d_dataset);
194 /* the GData struct *must* already be unlinked
195 * when invoking the destroy function
197 if (list->destroy_func)
198 list->destroy_func (list->data);
200 if (g_data_cache_length < G_DATA_CACHE_MAX)
202 list->next = g_data_cache;
204 g_data_cache_length++;
207 g_mem_chunk_free (g_data_mem_chunk, list);
220 if (list->id == key_id)
222 if (!list->destroy_func)
225 list->destroy_func = destroy_func;
229 register GDestroyNotify dfunc;
230 register gpointer ddata;
232 dfunc = list->destroy_func;
235 list->destroy_func = destroy_func;
237 /* we need to have updated all structures prior to
238 * invokation of the destroy function
252 g_data_cache = list->next;
253 g_data_cache_length--;
256 list = g_chunk_new (GData, g_data_mem_chunk);
257 list->next = *datalist;
260 list->destroy_func = destroy_func;
266 g_dataset_id_set_data_full (gconstpointer dataset_location,
269 GDestroyNotify destroy_func)
271 register GDataset *dataset;
273 g_return_if_fail (dataset_location != NULL);
277 g_return_if_fail (key_id > 0);
282 if (!g_dataset_location_ht)
283 g_data_initialize ();
285 dataset = g_dataset_lookup (dataset_location);
288 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
289 dataset->location = dataset_location;
290 dataset->datalist = NULL;
291 g_hash_table_insert (g_dataset_location_ht,
292 (gpointer) dataset->location,
296 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
300 g_datalist_id_set_data_full (gpointer *datalist,
303 GDestroyNotify destroy_func)
305 g_return_if_fail (datalist != NULL);
309 g_return_if_fail (key_id > 0);
314 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
318 g_dataset_id_set_destroy (gconstpointer dataset_location,
320 GDestroyNotify destroy_func)
322 register GDataset *dataset;
324 g_return_if_fail (dataset_location != NULL);
325 g_return_if_fail (key_id > 0);
327 if (g_dataset_location_ht)
329 dataset = g_dataset_lookup (dataset_location);
332 register GData *list;
334 for (list = dataset->datalist; list; list = list->next)
335 if (list->id == key_id)
337 list->destroy_func = destroy_func;
345 g_datalist_id_set_destroy (gpointer *datalist,
347 GDestroyNotify destroy_func)
349 register GData *list;
351 g_return_if_fail (datalist != NULL);
352 g_return_if_fail (key_id > 0);
354 for (list = *datalist; list; list = list->next)
355 if (list->id == key_id)
357 list->destroy_func = destroy_func;
363 g_dataset_id_get_data (gconstpointer dataset_location,
366 g_return_val_if_fail (dataset_location != NULL, NULL);
368 if (key_id && g_dataset_location_ht)
370 register GDataset *dataset;
372 dataset = g_dataset_lookup (dataset_location);
375 register GData *list;
377 for (list = dataset->datalist; list; list = list->next)
378 if (list->id == key_id)
387 g_datalist_id_get_data (gpointer *datalist,
390 g_return_val_if_fail (datalist != NULL, NULL);
394 register GData *list;
396 for (list = *datalist; list; list = list->next)
397 if (list->id == key_id)
405 g_datalist_init (gpointer *datalist)
407 g_return_if_fail (datalist != NULL);
413 g_data_initialize (void)
415 if (!g_dataset_location_ht)
417 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
418 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
419 g_dataset_cached = NULL;
420 g_dataset_mem_chunk =
421 g_mem_chunk_new ("GDataset MemChunk",
423 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
426 g_mem_chunk_new ("GData MemChunk",
428 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
434 g_quark_try_string (const gchar *string)
436 g_return_val_if_fail (string != NULL, 0);
439 return (gulong) g_hash_table_lookup (g_quark_ht, string);
445 g_quark_from_string (const gchar *string)
449 g_return_val_if_fail (string != NULL, 0);
452 g_data_initialize ();
454 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
456 quark = g_quark_new (g_strdup (string));
462 g_quark_from_static_string (const gchar *string)
466 g_return_val_if_fail (string != NULL, 0);
469 g_data_initialize ();
471 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
473 quark = g_quark_new (string);
479 g_quark_to_string (GQuark quark)
481 if (quark > 0 && quark <= g_quark_seq_id)
482 return g_quarks[quark - 1];
488 g_quark_new (const gchar *string)
492 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
493 g_quarks = g_realloc (g_quarks,
494 (g_quark_seq_id + G_QUARK_BLOCK_SIZE) * sizeof (gchar*));
497 g_quarks[g_quark_seq_id] = (gchar*) string;
499 quark = g_quark_seq_id;
500 g_hash_table_insert (g_quark_ht, (gchar*) string, GUINT_TO_POINTER (quark));