00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <string.h>
00035 #include "glib.h"
00036
00037
00038
00039
00040 #define G_QUARK_BLOCK_SIZE (512)
00041 #define G_DATA_MEM_CHUNK_PREALLOC (128)
00042 #define G_DATA_CACHE_MAX (512)
00043 #define G_DATASET_MEM_CHUNK_PREALLOC (32)
00044
00045
00046
00047 typedef struct _GDataset GDataset;
00048 struct _GData
00049 {
00050 GData *next;
00051 GQuark id;
00052 gpointer data;
00053 GDestroyNotify destroy_func;
00054 };
00055
00056 struct _GDataset
00057 {
00058 gconstpointer location;
00059 GData *datalist;
00060 };
00061
00062
00063
00064 static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
00065 static inline void g_datalist_clear_i (GData **datalist);
00066 static void g_dataset_destroy_internal (GDataset *dataset);
00067 static inline void g_data_set_internal (GData **datalist,
00068 GQuark key_id,
00069 gpointer data,
00070 GDestroyNotify destroy_func,
00071 GDataset *dataset);
00072 static void g_data_initialize (void);
00073 static inline GQuark g_quark_new (gchar *string);
00074
00075
00076
00077 G_LOCK_DEFINE_STATIC (g_dataset_global);
00078 static GHashTable *g_dataset_location_ht = NULL;
00079 static GDataset *g_dataset_cached = NULL;
00080
00081 static GMemChunk *g_dataset_mem_chunk = NULL;
00082 static GMemChunk *g_data_mem_chunk = NULL;
00083 static GData *g_data_cache = NULL;
00084 static guint g_data_cache_length = 0;
00085
00086 G_LOCK_DEFINE_STATIC (g_quark_global);
00087 static GHashTable *g_quark_ht = NULL;
00088 static gchar **g_quarks = NULL;
00089 static GQuark g_quark_seq_id = 0;
00090
00091
00092
00093
00094
00095 static inline void
00096 g_datalist_clear_i (GData **datalist)
00097 {
00098 register GData *list;
00099
00100
00101
00102 list = *datalist;
00103 *datalist = NULL;
00104
00105 while (list)
00106 {
00107 register GData *prev;
00108
00109 prev = list;
00110 list = prev->next;
00111
00112 if (prev->destroy_func)
00113 {
00114 G_UNLOCK (g_dataset_global);
00115 prev->destroy_func (prev->data);
00116 G_LOCK (g_dataset_global);
00117 }
00118
00119 if (g_data_cache_length < G_DATA_CACHE_MAX)
00120 {
00121 prev->next = g_data_cache;
00122 g_data_cache = prev;
00123 g_data_cache_length++;
00124 }
00125 else
00126 g_mem_chunk_free (g_data_mem_chunk, prev);
00127 }
00128 }
00129
00130 void
00131 g_datalist_clear (GData **datalist)
00132 {
00133 g_return_if_fail (datalist != NULL);
00134
00135 G_LOCK (g_dataset_global);
00136 if (!g_dataset_location_ht)
00137 g_data_initialize ();
00138
00139 while (*datalist)
00140 g_datalist_clear_i (datalist);
00141 G_UNLOCK (g_dataset_global);
00142 }
00143
00144
00145 static inline GDataset*
00146 g_dataset_lookup (gconstpointer dataset_location)
00147 {
00148 register GDataset *dataset;
00149
00150 if (g_dataset_cached && g_dataset_cached->location == dataset_location)
00151 return g_dataset_cached;
00152
00153 dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
00154 if (dataset)
00155 g_dataset_cached = dataset;
00156
00157 return dataset;
00158 }
00159
00160
00161 static void
00162 g_dataset_destroy_internal (GDataset *dataset)
00163 {
00164 register gconstpointer dataset_location;
00165
00166 dataset_location = dataset->location;
00167 while (dataset)
00168 {
00169 if (!dataset->datalist)
00170 {
00171 if (dataset == g_dataset_cached)
00172 g_dataset_cached = NULL;
00173 g_hash_table_remove (g_dataset_location_ht, dataset_location);
00174 g_mem_chunk_free (g_dataset_mem_chunk, dataset);
00175 break;
00176 }
00177
00178 g_datalist_clear_i (&dataset->datalist);
00179 dataset = g_dataset_lookup (dataset_location);
00180 }
00181 }
00182
00183 void
00184 g_dataset_destroy (gconstpointer dataset_location)
00185 {
00186 g_return_if_fail (dataset_location != NULL);
00187
00188 G_LOCK (g_dataset_global);
00189 if (g_dataset_location_ht)
00190 {
00191 register GDataset *dataset;
00192
00193 dataset = g_dataset_lookup (dataset_location);
00194 if (dataset)
00195 g_dataset_destroy_internal (dataset);
00196 }
00197 G_UNLOCK (g_dataset_global);
00198 }
00199
00200
00201 static inline void
00202 g_data_set_internal (GData **datalist,
00203 GQuark key_id,
00204 gpointer data,
00205 GDestroyNotify destroy_func,
00206 GDataset *dataset)
00207 {
00208 register GData *list;
00209
00210 list = *datalist;
00211 if (!data)
00212 {
00213 register GData *prev;
00214
00215 prev = NULL;
00216 while (list)
00217 {
00218 if (list->id == key_id)
00219 {
00220 if (prev)
00221 prev->next = list->next;
00222 else
00223 {
00224 *datalist = list->next;
00225
00226
00227
00228
00229 if (!*datalist && dataset)
00230 g_dataset_destroy_internal (dataset);
00231 }
00232
00233
00234
00235
00236
00237
00238
00239 if (list->destroy_func && !destroy_func)
00240 {
00241 G_UNLOCK (g_dataset_global);
00242 list->destroy_func (list->data);
00243 G_LOCK (g_dataset_global);
00244 }
00245
00246 if (g_data_cache_length < G_DATA_CACHE_MAX)
00247 {
00248 list->next = g_data_cache;
00249 g_data_cache = list;
00250 g_data_cache_length++;
00251 }
00252 else
00253 g_mem_chunk_free (g_data_mem_chunk, list);
00254
00255 return;
00256 }
00257
00258 prev = list;
00259 list = list->next;
00260 }
00261 }
00262 else
00263 {
00264 while (list)
00265 {
00266 if (list->id == key_id)
00267 {
00268 if (!list->destroy_func)
00269 {
00270 list->data = data;
00271 list->destroy_func = destroy_func;
00272 }
00273 else
00274 {
00275 register GDestroyNotify dfunc;
00276 register gpointer ddata;
00277
00278 dfunc = list->destroy_func;
00279 ddata = list->data;
00280 list->data = data;
00281 list->destroy_func = destroy_func;
00282
00283
00284
00285
00286 G_UNLOCK (g_dataset_global);
00287 dfunc (ddata);
00288 G_LOCK (g_dataset_global);
00289 }
00290
00291 return;
00292 }
00293
00294 list = list->next;
00295 }
00296
00297 if (g_data_cache)
00298 {
00299 list = g_data_cache;
00300 g_data_cache = list->next;
00301 g_data_cache_length--;
00302 }
00303 else
00304 list = g_chunk_new (GData, g_data_mem_chunk);
00305 list->next = *datalist;
00306 list->id = key_id;
00307 list->data = data;
00308 list->destroy_func = destroy_func;
00309 *datalist = list;
00310 }
00311 }
00312
00313 void
00314 g_dataset_id_set_data_full (gconstpointer dataset_location,
00315 GQuark key_id,
00316 gpointer data,
00317 GDestroyNotify destroy_func)
00318 {
00319 register GDataset *dataset;
00320
00321 g_return_if_fail (dataset_location != NULL);
00322 if (!data)
00323 g_return_if_fail (destroy_func == NULL);
00324 if (!key_id)
00325 {
00326 if (data)
00327 g_return_if_fail (key_id > 0);
00328 else
00329 return;
00330 }
00331
00332 G_LOCK (g_dataset_global);
00333 if (!g_dataset_location_ht)
00334 g_data_initialize ();
00335
00336 dataset = g_dataset_lookup (dataset_location);
00337 if (!dataset)
00338 {
00339 dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
00340 dataset->location = dataset_location;
00341 g_datalist_init (&dataset->datalist);
00342 g_hash_table_insert (g_dataset_location_ht,
00343 (gpointer) dataset->location,
00344 dataset);
00345 }
00346
00347 g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
00348 G_UNLOCK (g_dataset_global);
00349 }
00350
00351 void
00352 g_datalist_id_set_data_full (GData **datalist,
00353 GQuark key_id,
00354 gpointer data,
00355 GDestroyNotify destroy_func)
00356 {
00357 g_return_if_fail (datalist != NULL);
00358 if (!data)
00359 g_return_if_fail (destroy_func == NULL);
00360 if (!key_id)
00361 {
00362 if (data)
00363 g_return_if_fail (key_id > 0);
00364 else
00365 return;
00366 }
00367
00368 G_LOCK (g_dataset_global);
00369 if (!g_dataset_location_ht)
00370 g_data_initialize ();
00371
00372 g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
00373 G_UNLOCK (g_dataset_global);
00374 }
00375
00376 void
00377 g_dataset_id_remove_no_notify (gconstpointer dataset_location,
00378 GQuark key_id)
00379 {
00380 g_return_if_fail (dataset_location != NULL);
00381
00382 G_LOCK (g_dataset_global);
00383 if (key_id && g_dataset_location_ht)
00384 {
00385 GDataset *dataset;
00386
00387 dataset = g_dataset_lookup (dataset_location);
00388 if (dataset)
00389 g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
00390 }
00391 G_UNLOCK (g_dataset_global);
00392 }
00393
00394 void
00395 g_datalist_id_remove_no_notify (GData **datalist,
00396 GQuark key_id)
00397 {
00398 g_return_if_fail (datalist != NULL);
00399
00400 G_LOCK (g_dataset_global);
00401 if (key_id && g_dataset_location_ht)
00402 g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
00403 G_UNLOCK (g_dataset_global);
00404 }
00405
00406 gpointer
00407 g_dataset_id_get_data (gconstpointer dataset_location,
00408 GQuark key_id)
00409 {
00410 g_return_val_if_fail (dataset_location != NULL, NULL);
00411
00412 G_LOCK (g_dataset_global);
00413 if (key_id && g_dataset_location_ht)
00414 {
00415 register GDataset *dataset;
00416
00417 dataset = g_dataset_lookup (dataset_location);
00418 if (dataset)
00419 {
00420 register GData *list;
00421
00422 for (list = dataset->datalist; list; list = list->next)
00423 if (list->id == key_id)
00424 {
00425 G_UNLOCK (g_dataset_global);
00426 return list->data;
00427 }
00428 }
00429 }
00430 G_UNLOCK (g_dataset_global);
00431
00432 return NULL;
00433 }
00434
00435 gpointer
00436 g_datalist_id_get_data (GData **datalist,
00437 GQuark key_id)
00438 {
00439 g_return_val_if_fail (datalist != NULL, NULL);
00440
00441 if (key_id)
00442 {
00443 register GData *list;
00444
00445 for (list = *datalist; list; list = list->next)
00446 if (list->id == key_id)
00447 return list->data;
00448 }
00449
00450 return NULL;
00451 }
00452
00453 void
00454 g_dataset_foreach (gconstpointer dataset_location,
00455 GDataForeachFunc func,
00456 gpointer user_data)
00457 {
00458 register GDataset *dataset;
00459
00460 g_return_if_fail (dataset_location != NULL);
00461 g_return_if_fail (func != NULL);
00462
00463 G_LOCK (g_dataset_global);
00464 if (g_dataset_location_ht)
00465 {
00466 dataset = g_dataset_lookup (dataset_location);
00467 G_UNLOCK (g_dataset_global);
00468 if (dataset)
00469 {
00470 register GData *list;
00471
00472 for (list = dataset->datalist; list; list = list->next)
00473 func (list->id, list->data, user_data);
00474 }
00475 }
00476 else
00477 {
00478 G_UNLOCK (g_dataset_global);
00479 }
00480 }
00481
00482 void
00483 g_datalist_foreach (GData **datalist,
00484 GDataForeachFunc func,
00485 gpointer user_data)
00486 {
00487 register GData *list;
00488
00489 g_return_if_fail (datalist != NULL);
00490 g_return_if_fail (func != NULL);
00491
00492 for (list = *datalist; list; list = list->next)
00493 func (list->id, list->data, user_data);
00494 }
00495
00496 void
00497 g_datalist_init (GData **datalist)
00498 {
00499 g_return_if_fail (datalist != NULL);
00500
00501 *datalist = NULL;
00502 }
00503
00504
00505 static void
00506 g_data_initialize (void)
00507 {
00508 g_return_if_fail (g_dataset_location_ht == NULL);
00509
00510 g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
00511 g_dataset_cached = NULL;
00512 g_dataset_mem_chunk =
00513 g_mem_chunk_new ("GDataset MemChunk",
00514 sizeof (GDataset),
00515 sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
00516 G_ALLOC_AND_FREE);
00517 g_data_mem_chunk =
00518 g_mem_chunk_new ("GData MemChunk",
00519 sizeof (GData),
00520 sizeof (GData) * G_DATA_MEM_CHUNK_PREALLOC,
00521 G_ALLOC_AND_FREE);
00522 }
00523
00524 GQuark
00525 g_quark_try_string (const gchar *string)
00526 {
00527 GQuark quark = 0;
00528 g_return_val_if_fail (string != NULL, 0);
00529
00530 G_LOCK (g_quark_global);
00531 if (g_quark_ht)
00532 quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
00533 G_UNLOCK (g_quark_global);
00534
00535 return quark;
00536 }
00537
00538 GQuark
00539 g_quark_from_string (const gchar *string)
00540 {
00541 GQuark quark;
00542
00543 g_return_val_if_fail (string != NULL, 0);
00544
00545 G_LOCK (g_quark_global);
00546 if (g_quark_ht)
00547 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
00548 else
00549 {
00550 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
00551 quark = 0;
00552 }
00553
00554 if (!quark)
00555 quark = g_quark_new (g_strdup (string));
00556 G_UNLOCK (g_quark_global);
00557
00558 return quark;
00559 }
00560
00561 GQuark
00562 g_quark_from_static_string (const gchar *string)
00563 {
00564 GQuark quark;
00565
00566 g_return_val_if_fail (string != NULL, 0);
00567
00568 G_LOCK (g_quark_global);
00569 if (g_quark_ht)
00570 quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
00571 else
00572 {
00573 g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
00574 quark = 0;
00575 }
00576
00577 if (!quark)
00578 quark = g_quark_new ((gchar*) string);
00579 G_UNLOCK (g_quark_global);
00580
00581 return quark;
00582 }
00583
00584 gchar*
00585 g_quark_to_string (GQuark quark)
00586 {
00587 gchar* result = NULL;
00588 G_LOCK (g_quark_global);
00589 if (quark > 0 && quark <= g_quark_seq_id)
00590 result = g_quarks[quark - 1];
00591 G_UNLOCK (g_quark_global);
00592
00593 return result;
00594 }
00595
00596
00597 static inline GQuark
00598 g_quark_new (gchar *string)
00599 {
00600 GQuark quark;
00601
00602 if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
00603 g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
00604
00605 g_quarks[g_quark_seq_id] = string;
00606 g_quark_seq_id++;
00607 quark = g_quark_seq_id;
00608 g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
00609
00610 return quark;
00611 }