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 (gchar *string);
63 /* --- variables --- */
64 static GHashTable *g_dataset_location_ht = NULL;
65 static GDataset *g_dataset_cached = NULL;
66 static GMemChunk *g_dataset_mem_chunk = NULL;
67 static GMemChunk *g_data_mem_chunk = NULL;
68 static GData *g_data_cache = NULL;
69 static guint g_data_cache_length = 0;
70 static GHashTable *g_quark_ht = NULL;
71 static gchar **g_quarks = NULL;
72 static GQuark g_quark_seq_id = 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);
112 if (!g_dataset_location_ht)
113 g_data_initialize ();
116 g_datalist_clear_i (datalist);
119 static inline GDataset*
120 g_dataset_lookup (gconstpointer dataset_location)
122 register GDataset *dataset;
124 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
125 return g_dataset_cached;
127 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
129 g_dataset_cached = dataset;
135 g_dataset_destroy_internal (GDataset *dataset)
137 register gconstpointer dataset_location;
139 dataset_location = dataset->location;
142 if (!dataset->datalist)
144 if (dataset == g_dataset_cached)
145 g_dataset_cached = NULL;
146 g_hash_table_remove (g_dataset_location_ht, dataset_location);
147 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
151 g_datalist_clear_i (&dataset->datalist);
152 dataset = g_dataset_lookup (dataset_location);
157 g_dataset_destroy (gconstpointer dataset_location)
159 g_return_if_fail (dataset_location != NULL);
161 if (g_dataset_location_ht)
163 register GDataset *dataset;
165 dataset = g_dataset_lookup (dataset_location);
167 g_dataset_destroy_internal (dataset);
172 g_data_set_internal (GData **datalist,
175 GDestroyNotify destroy_func,
178 register GData *list;
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 if (!g_dataset_location_ht)
331 g_data_initialize ();
333 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
337 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
340 g_return_if_fail (dataset_location != NULL);
342 if (key_id && g_dataset_location_ht)
346 dataset = g_dataset_lookup (dataset_location);
348 g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
353 g_datalist_id_remove_no_notify (GData **datalist,
356 g_return_if_fail (datalist != NULL);
358 if (key_id && g_dataset_location_ht)
359 g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
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 (GData **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_dataset_foreach (gconstpointer dataset_location,
406 GDataForeachFunc func,
409 register GDataset *dataset;
411 g_return_if_fail (dataset_location != NULL);
412 g_return_if_fail (func != NULL);
414 if (g_dataset_location_ht)
416 dataset = g_dataset_lookup (dataset_location);
419 register GData *list;
421 for (list = dataset->datalist; list; list = list->next)
422 func (list->id, list->data, user_data);
428 g_datalist_foreach (GData **datalist,
429 GDataForeachFunc func,
432 register GData *list;
434 g_return_if_fail (datalist != NULL);
435 g_return_if_fail (func != NULL);
437 for (list = *datalist; list; list = list->next)
438 func (list->id, list->data, user_data);
442 g_datalist_init (GData **datalist)
444 g_return_if_fail (datalist != NULL);
450 g_data_initialize (void)
452 g_return_if_fail (g_dataset_location_ht == NULL);
454 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
455 g_dataset_cached = NULL;
456 g_dataset_mem_chunk =
457 g_mem_chunk_new ("GDataset MemChunk",
459 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
462 g_mem_chunk_new ("GData MemChunk",
464 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
469 g_quark_try_string (const gchar *string)
471 g_return_val_if_fail (string != NULL, 0);
474 return (gulong) g_hash_table_lookup (g_quark_ht, string);
480 g_quark_from_string (const gchar *string)
484 g_return_val_if_fail (string != NULL, 0);
487 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
490 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
495 quark = g_quark_new (g_strdup (string));
501 g_quark_from_static_string (const gchar *string)
505 g_return_val_if_fail (string != NULL, 0);
508 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
511 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
516 quark = g_quark_new ((gchar*) string);
522 g_quark_to_string (GQuark quark)
524 if (quark > 0 && quark <= g_quark_seq_id)
525 return g_quarks[quark - 1];
531 g_quark_new (gchar *string)
535 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
536 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
538 g_quarks[g_quark_seq_id] = string;
540 quark = g_quark_seq_id;
541 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));