Some inline docs fixes.
[glib.git] / gdataset.c
blob020b1e70db8acbc113d4a8ece09aca4f695c208b
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 Lesser 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 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser 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.
23 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
24 * file for a list of people on the GLib Team. See the ChangeLog
25 * files for a list of changes. These files are distributed with
26 * GLib at ftp://ftp.gtk.org/pub/gtk/.
29 /*
30 * MT safe ; FIXME: might still freeze, watch out, not thoroughly
31 * looked at yet.
34 #include <string.h>
35 #include "glib.h"
39 /* --- defines --- */
40 #define G_QUARK_BLOCK_SIZE (512)
41 #define G_DATA_MEM_CHUNK_PREALLOC (128)
42 #define G_DATA_CACHE_MAX (512)
43 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
46 /* --- structures --- */
47 typedef struct _GDataset GDataset;
48 struct _GData
50 GData *next;
51 GQuark id;
52 gpointer data;
53 GDestroyNotify destroy_func;
56 struct _GDataset
58 gconstpointer location;
59 GData *datalist;
63 /* --- prototypes --- */
64 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
65 static inline void g_datalist_clear_i (GData **datalist);
66 static void g_dataset_destroy_internal (GDataset *dataset);
67 static inline gpointer g_data_set_internal (GData **datalist,
68 GQuark key_id,
69 gpointer data,
70 GDestroyNotify destroy_func,
71 GDataset *dataset);
72 static void g_data_initialize (void);
73 static inline GQuark g_quark_new (gchar *string);
76 /* --- variables --- */
77 G_LOCK_DEFINE_STATIC (g_dataset_global);
78 static GHashTable *g_dataset_location_ht = NULL;
79 static GDataset *g_dataset_cached = NULL; /* should this be
80 threadspecific? */
81 static GMemChunk *g_dataset_mem_chunk = NULL;
82 static GMemChunk *g_data_mem_chunk = NULL;
83 static GData *g_data_cache = NULL;
84 static guint g_data_cache_length = 0;
86 G_LOCK_DEFINE_STATIC (g_quark_global);
87 static GHashTable *g_quark_ht = NULL;
88 static gchar **g_quarks = NULL;
89 static GQuark g_quark_seq_id = 0;
92 /* --- functions --- */
94 /* HOLDS: g_dataset_global_lock */
95 static inline void
96 g_datalist_clear_i (GData **datalist)
98 register GData *list;
100 /* unlink *all* items before walking their destructors
102 list = *datalist;
103 *datalist = NULL;
105 while (list)
107 register GData *prev;
109 prev = list;
110 list = prev->next;
112 if (prev->destroy_func)
114 G_UNLOCK (g_dataset_global);
115 prev->destroy_func (prev->data);
116 G_LOCK (g_dataset_global);
119 if (g_data_cache_length < G_DATA_CACHE_MAX)
121 prev->next = g_data_cache;
122 g_data_cache = prev;
123 g_data_cache_length++;
125 else
126 g_mem_chunk_free (g_data_mem_chunk, prev);
130 void
131 g_datalist_clear (GData **datalist)
133 g_return_if_fail (datalist != NULL);
135 G_LOCK (g_dataset_global);
136 if (!g_dataset_location_ht)
137 g_data_initialize ();
139 while (*datalist)
140 g_datalist_clear_i (datalist);
141 G_UNLOCK (g_dataset_global);
144 /* HOLDS: g_dataset_global_lock */
145 static inline GDataset*
146 g_dataset_lookup (gconstpointer dataset_location)
148 register GDataset *dataset;
150 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
151 return g_dataset_cached;
153 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
154 if (dataset)
155 g_dataset_cached = dataset;
157 return dataset;
160 /* HOLDS: g_dataset_global_lock */
161 static void
162 g_dataset_destroy_internal (GDataset *dataset)
164 register gconstpointer dataset_location;
166 dataset_location = dataset->location;
167 while (dataset)
169 if (!dataset->datalist)
171 if (dataset == g_dataset_cached)
172 g_dataset_cached = NULL;
173 g_hash_table_remove (g_dataset_location_ht, dataset_location);
174 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
175 break;
178 g_datalist_clear_i (&dataset->datalist);
179 dataset = g_dataset_lookup (dataset_location);
183 void
184 g_dataset_destroy (gconstpointer dataset_location)
186 g_return_if_fail (dataset_location != NULL);
188 G_LOCK (g_dataset_global);
189 if (g_dataset_location_ht)
191 register GDataset *dataset;
193 dataset = g_dataset_lookup (dataset_location);
194 if (dataset)
195 g_dataset_destroy_internal (dataset);
197 G_UNLOCK (g_dataset_global);
200 /* HOLDS: g_dataset_global_lock */
201 static inline gpointer
202 g_data_set_internal (GData **datalist,
203 GQuark key_id,
204 gpointer data,
205 GDestroyNotify destroy_func,
206 GDataset *dataset)
208 register GData *list;
210 list = *datalist;
211 if (!data)
213 register GData *prev;
215 prev = NULL;
216 while (list)
218 if (list->id == key_id)
220 gpointer ret_data = NULL;
222 if (prev)
223 prev->next = list->next;
224 else
226 *datalist = list->next;
228 /* the dataset destruction *must* be done
229 * prior to invokation of the data destroy function
231 if (!*datalist && dataset)
232 g_dataset_destroy_internal (dataset);
235 /* the GData struct *must* already be unlinked
236 * when invoking the destroy function.
237 * we use (data==NULL && destroy_func!=NULL) as
238 * a special hint combination to "steal"
239 * data without destroy notification
241 if (list->destroy_func && !destroy_func)
243 G_UNLOCK (g_dataset_global);
244 list->destroy_func (list->data);
245 G_LOCK (g_dataset_global);
247 else
248 ret_data = list->data;
250 if (g_data_cache_length < G_DATA_CACHE_MAX)
252 list->next = g_data_cache;
253 g_data_cache = list;
254 g_data_cache_length++;
256 else
257 g_mem_chunk_free (g_data_mem_chunk, list);
259 return ret_data;
262 prev = list;
263 list = list->next;
266 else
268 while (list)
270 if (list->id == key_id)
272 if (!list->destroy_func)
274 list->data = data;
275 list->destroy_func = destroy_func;
277 else
279 register GDestroyNotify dfunc;
280 register gpointer ddata;
282 dfunc = list->destroy_func;
283 ddata = list->data;
284 list->data = data;
285 list->destroy_func = destroy_func;
287 /* we need to have updated all structures prior to
288 * invokation of the destroy function
290 G_UNLOCK (g_dataset_global);
291 dfunc (ddata);
292 G_LOCK (g_dataset_global);
295 return NULL;
298 list = list->next;
301 if (g_data_cache)
303 list = g_data_cache;
304 g_data_cache = list->next;
305 g_data_cache_length--;
307 else
308 list = g_chunk_new (GData, g_data_mem_chunk);
309 list->next = *datalist;
310 list->id = key_id;
311 list->data = data;
312 list->destroy_func = destroy_func;
313 *datalist = list;
316 return NULL;
319 void
320 g_dataset_id_set_data_full (gconstpointer dataset_location,
321 GQuark key_id,
322 gpointer data,
323 GDestroyNotify destroy_func)
325 register GDataset *dataset;
327 g_return_if_fail (dataset_location != NULL);
328 if (!data)
329 g_return_if_fail (destroy_func == NULL);
330 if (!key_id)
332 if (data)
333 g_return_if_fail (key_id > 0);
334 else
335 return;
338 G_LOCK (g_dataset_global);
339 if (!g_dataset_location_ht)
340 g_data_initialize ();
342 dataset = g_dataset_lookup (dataset_location);
343 if (!dataset)
345 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
346 dataset->location = dataset_location;
347 g_datalist_init (&dataset->datalist);
348 g_hash_table_insert (g_dataset_location_ht,
349 (gpointer) dataset->location,
350 dataset);
353 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
354 G_UNLOCK (g_dataset_global);
357 void
358 g_datalist_id_set_data_full (GData **datalist,
359 GQuark key_id,
360 gpointer data,
361 GDestroyNotify destroy_func)
363 g_return_if_fail (datalist != NULL);
364 if (!data)
365 g_return_if_fail (destroy_func == NULL);
366 if (!key_id)
368 if (data)
369 g_return_if_fail (key_id > 0);
370 else
371 return;
374 G_LOCK (g_dataset_global);
375 if (!g_dataset_location_ht)
376 g_data_initialize ();
378 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
379 G_UNLOCK (g_dataset_global);
382 gpointer
383 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
384 GQuark key_id)
386 gpointer ret_data = NULL;
388 g_return_val_if_fail (dataset_location != NULL, NULL);
390 G_LOCK (g_dataset_global);
391 if (key_id && g_dataset_location_ht)
393 GDataset *dataset;
395 dataset = g_dataset_lookup (dataset_location);
396 if (dataset)
397 ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
399 G_UNLOCK (g_dataset_global);
401 return ret_data;
404 gpointer
405 g_datalist_id_remove_no_notify (GData **datalist,
406 GQuark key_id)
408 gpointer ret_data = NULL;
410 g_return_val_if_fail (datalist != NULL, NULL);
412 G_LOCK (g_dataset_global);
413 if (key_id && g_dataset_location_ht)
414 ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
415 G_UNLOCK (g_dataset_global);
417 return ret_data;
420 gpointer
421 g_dataset_id_get_data (gconstpointer dataset_location,
422 GQuark key_id)
424 g_return_val_if_fail (dataset_location != NULL, NULL);
426 G_LOCK (g_dataset_global);
427 if (key_id && g_dataset_location_ht)
429 register GDataset *dataset;
431 dataset = g_dataset_lookup (dataset_location);
432 if (dataset)
434 register GData *list;
436 for (list = dataset->datalist; list; list = list->next)
437 if (list->id == key_id)
439 G_UNLOCK (g_dataset_global);
440 return list->data;
444 G_UNLOCK (g_dataset_global);
446 return NULL;
449 gpointer
450 g_datalist_id_get_data (GData **datalist,
451 GQuark key_id)
453 g_return_val_if_fail (datalist != NULL, NULL);
455 if (key_id)
457 register GData *list;
459 for (list = *datalist; list; list = list->next)
460 if (list->id == key_id)
461 return list->data;
464 return NULL;
467 void
468 g_dataset_foreach (gconstpointer dataset_location,
469 GDataForeachFunc func,
470 gpointer user_data)
472 register GDataset *dataset;
474 g_return_if_fail (dataset_location != NULL);
475 g_return_if_fail (func != NULL);
477 G_LOCK (g_dataset_global);
478 if (g_dataset_location_ht)
480 dataset = g_dataset_lookup (dataset_location);
481 G_UNLOCK (g_dataset_global);
482 if (dataset)
484 register GData *list;
486 for (list = dataset->datalist; list; list = list->next)
487 func (list->id, list->data, user_data);
490 else
492 G_UNLOCK (g_dataset_global);
496 void
497 g_datalist_foreach (GData **datalist,
498 GDataForeachFunc func,
499 gpointer user_data)
501 register GData *list;
503 g_return_if_fail (datalist != NULL);
504 g_return_if_fail (func != NULL);
506 for (list = *datalist; list; list = list->next)
507 func (list->id, list->data, user_data);
510 void
511 g_datalist_init (GData **datalist)
513 g_return_if_fail (datalist != NULL);
515 *datalist = NULL;
518 /* HOLDS: g_dataset_global_lock */
519 static void
520 g_data_initialize (void)
522 g_return_if_fail (g_dataset_location_ht == NULL);
524 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
525 g_dataset_cached = NULL;
526 g_dataset_mem_chunk =
527 g_mem_chunk_new ("GDataset MemChunk",
528 sizeof (GDataset),
529 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
530 G_ALLOC_AND_FREE);
531 g_data_mem_chunk =
532 g_mem_chunk_new ("GData MemChunk",
533 sizeof (GData),
534 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
535 G_ALLOC_AND_FREE);
538 GQuark
539 g_quark_try_string (const gchar *string)
541 GQuark quark = 0;
542 g_return_val_if_fail (string != NULL, 0);
544 G_LOCK (g_quark_global);
545 if (g_quark_ht)
546 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
547 G_UNLOCK (g_quark_global);
549 return quark;
552 GQuark
553 g_quark_from_string (const gchar *string)
555 GQuark quark;
557 g_return_val_if_fail (string != NULL, 0);
559 G_LOCK (g_quark_global);
560 if (g_quark_ht)
561 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
562 else
564 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
565 quark = 0;
568 if (!quark)
569 quark = g_quark_new (g_strdup (string));
570 G_UNLOCK (g_quark_global);
572 return quark;
575 GQuark
576 g_quark_from_static_string (const gchar *string)
578 GQuark quark;
580 g_return_val_if_fail (string != NULL, 0);
582 G_LOCK (g_quark_global);
583 if (g_quark_ht)
584 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
585 else
587 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
588 quark = 0;
591 if (!quark)
592 quark = g_quark_new ((gchar*) string);
593 G_UNLOCK (g_quark_global);
595 return quark;
598 gchar*
599 g_quark_to_string (GQuark quark)
601 gchar* result = NULL;
602 G_LOCK (g_quark_global);
603 if (quark > 0 && quark <= g_quark_seq_id)
604 result = g_quarks[quark - 1];
605 G_UNLOCK (g_quark_global);
607 return result;
610 /* HOLDS: g_quark_global_lock */
611 static inline GQuark
612 g_quark_new (gchar *string)
614 GQuark quark;
616 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
617 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
619 g_quarks[g_quark_seq_id] = string;
620 g_quark_seq_id++;
621 quark = g_quark_seq_id;
622 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
624 return quark;