/src/irssi/subprojects/glib-2.74.3/glib/gdataset.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GLIB - Library of useful routines for C programming |
2 | | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | | * |
4 | | * gdataset.c: Generic dataset mechanism, similar to GtkObject data. |
5 | | * Copyright (C) 1998 Tim Janik |
6 | | * |
7 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | /* |
24 | | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
25 | | * file for a list of people on the GLib Team. See the ChangeLog |
26 | | * files for a list of changes. These files are distributed with |
27 | | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
28 | | */ |
29 | | |
30 | | /* |
31 | | * MT safe ; except for g_data*_foreach() |
32 | | */ |
33 | | |
34 | | #include "config.h" |
35 | | |
36 | | #include <string.h> |
37 | | |
38 | | #include "gdataset.h" |
39 | | #include "gbitlock.h" |
40 | | |
41 | | #include "gslice.h" |
42 | | #include "gdatasetprivate.h" |
43 | | #include "ghash.h" |
44 | | #include "gquark.h" |
45 | | #include "gstrfuncs.h" |
46 | | #include "gtestutils.h" |
47 | | #include "gthread.h" |
48 | | #include "glib_trace.h" |
49 | | #include "galloca.h" |
50 | | |
51 | | /** |
52 | | * SECTION:datasets |
53 | | * @title: Datasets |
54 | | * @short_description: associate groups of data elements with |
55 | | * particular memory locations |
56 | | * |
57 | | * Datasets associate groups of data elements with particular memory |
58 | | * locations. These are useful if you need to associate data with a |
59 | | * structure returned from an external library. Since you cannot modify |
60 | | * the structure, you use its location in memory as the key into a |
61 | | * dataset, where you can associate any number of data elements with it. |
62 | | * |
63 | | * There are two forms of most of the dataset functions. The first form |
64 | | * uses strings to identify the data elements associated with a |
65 | | * location. The second form uses #GQuark identifiers, which are |
66 | | * created with a call to g_quark_from_string() or |
67 | | * g_quark_from_static_string(). The second form is quicker, since it |
68 | | * does not require looking up the string in the hash table of #GQuark |
69 | | * identifiers. |
70 | | * |
71 | | * There is no function to create a dataset. It is automatically |
72 | | * created as soon as you add elements to it. |
73 | | * |
74 | | * To add data elements to a dataset use g_dataset_id_set_data(), |
75 | | * g_dataset_id_set_data_full(), g_dataset_set_data() and |
76 | | * g_dataset_set_data_full(). |
77 | | * |
78 | | * To get data elements from a dataset use g_dataset_id_get_data() and |
79 | | * g_dataset_get_data(). |
80 | | * |
81 | | * To iterate over all data elements in a dataset use |
82 | | * g_dataset_foreach() (not thread-safe). |
83 | | * |
84 | | * To remove data elements from a dataset use |
85 | | * g_dataset_id_remove_data() and g_dataset_remove_data(). |
86 | | * |
87 | | * To destroy a dataset, use g_dataset_destroy(). |
88 | | **/ |
89 | | |
90 | | /** |
91 | | * SECTION:datalist |
92 | | * @title: Keyed Data Lists |
93 | | * @short_description: lists of data elements which are accessible by a |
94 | | * string or GQuark identifier |
95 | | * |
96 | | * Keyed data lists provide lists of arbitrary data elements which can |
97 | | * be accessed either with a string or with a #GQuark corresponding to |
98 | | * the string. |
99 | | * |
100 | | * The #GQuark methods are quicker, since the strings have to be |
101 | | * converted to #GQuarks anyway. |
102 | | * |
103 | | * Data lists are used for associating arbitrary data with #GObjects, |
104 | | * using g_object_set_data() and related functions. |
105 | | * |
106 | | * To create a datalist, use g_datalist_init(). |
107 | | * |
108 | | * To add data elements to a datalist use g_datalist_id_set_data(), |
109 | | * g_datalist_id_set_data_full(), g_datalist_set_data() and |
110 | | * g_datalist_set_data_full(). |
111 | | * |
112 | | * To get data elements from a datalist use g_datalist_id_get_data() |
113 | | * and g_datalist_get_data(). |
114 | | * |
115 | | * To iterate over all data elements in a datalist use |
116 | | * g_datalist_foreach() (not thread-safe). |
117 | | * |
118 | | * To remove data elements from a datalist use |
119 | | * g_datalist_id_remove_data() and g_datalist_remove_data(). |
120 | | * |
121 | | * To remove all data elements from a datalist, use g_datalist_clear(). |
122 | | **/ |
123 | | |
124 | | /** |
125 | | * GData: |
126 | | * |
127 | | * An opaque data structure that represents a keyed data list. |
128 | | * |
129 | | * See also: [Keyed data lists][glib-Keyed-Data-Lists]. |
130 | | **/ |
131 | | |
132 | | /** |
133 | | * GDestroyNotify: |
134 | | * @data: the data element. |
135 | | * |
136 | | * Specifies the type of function which is called when a data element |
137 | | * is destroyed. It is passed the pointer to the data element and |
138 | | * should free any memory and resources allocated for it. |
139 | | **/ |
140 | | |
141 | 8.64k | #define G_DATALIST_FLAGS_MASK_INTERNAL 0x7 |
142 | | |
143 | | /* datalist pointer accesses have to be carried out atomically */ |
144 | | #define G_DATALIST_GET_POINTER(datalist) \ |
145 | 4.32k | ((GData*) ((gsize) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK_INTERNAL)) |
146 | | |
147 | 4.32k | #define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \ |
148 | 4.32k | gpointer _oldv, _newv; \ |
149 | 4.32k | do { \ |
150 | 4.32k | _oldv = g_atomic_pointer_get (datalist); \ |
151 | 4.32k | _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK_INTERNAL) | (gsize) pointer); \ |
152 | 4.32k | } while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, _oldv, _newv)); \ |
153 | 4.32k | } G_STMT_END |
154 | | |
155 | | /* --- structures --- */ |
156 | | typedef struct { |
157 | | GQuark key; |
158 | | gpointer data; |
159 | | GDestroyNotify destroy; |
160 | | } GDataElt; |
161 | | |
162 | | typedef struct _GDataset GDataset; |
163 | | struct _GData |
164 | | { |
165 | | guint32 len; /* Number of elements */ |
166 | | guint32 alloc; /* Number of allocated elements */ |
167 | | GDataElt data[1]; /* Flexible array */ |
168 | | }; |
169 | | |
170 | | struct _GDataset |
171 | | { |
172 | | gconstpointer location; |
173 | | GData *datalist; |
174 | | }; |
175 | | |
176 | | |
177 | | /* --- prototypes --- */ |
178 | | static inline GDataset* g_dataset_lookup (gconstpointer dataset_location); |
179 | | static inline void g_datalist_clear_i (GData **datalist); |
180 | | static void g_dataset_destroy_internal (GDataset *dataset); |
181 | | static inline gpointer g_data_set_internal (GData **datalist, |
182 | | GQuark key_id, |
183 | | gpointer data, |
184 | | GDestroyNotify destroy_func, |
185 | | GDataset *dataset); |
186 | | static void g_data_initialize (void); |
187 | | |
188 | | /* Locking model: |
189 | | * Each standalone GDataList is protected by a bitlock in the datalist pointer, |
190 | | * which protects that modification of the non-flags part of the datalist pointer |
191 | | * and the contents of the datalist. |
192 | | * |
193 | | * For GDataSet we have a global lock g_dataset_global that protects |
194 | | * the global dataset hash and cache, and additionally it protects the |
195 | | * datalist such that we can avoid to use the bit lock in a few places |
196 | | * where it is easy. |
197 | | */ |
198 | | |
199 | | /* --- variables --- */ |
200 | | G_LOCK_DEFINE_STATIC (g_dataset_global); |
201 | | static GHashTable *g_dataset_location_ht = NULL; |
202 | | static GDataset *g_dataset_cached = NULL; /* should this be |
203 | | thread specific? */ |
204 | | |
205 | | /* --- functions --- */ |
206 | | |
207 | | #define DATALIST_LOCK_BIT 2 |
208 | | |
209 | | static void |
210 | | g_datalist_lock (GData **datalist) |
211 | 4.32k | { |
212 | 4.32k | g_pointer_bit_lock ((void **)datalist, DATALIST_LOCK_BIT); |
213 | 4.32k | } |
214 | | |
215 | | static void |
216 | | g_datalist_unlock (GData **datalist) |
217 | 4.32k | { |
218 | 4.32k | g_pointer_bit_unlock ((void **)datalist, DATALIST_LOCK_BIT); |
219 | 4.32k | } |
220 | | |
221 | | /* Called with the datalist lock held, or the dataset global |
222 | | * lock for dataset lists |
223 | | */ |
224 | | static void |
225 | | g_datalist_clear_i (GData **datalist) |
226 | 0 | { |
227 | 0 | GData *data; |
228 | 0 | guint i; |
229 | |
|
230 | 0 | data = G_DATALIST_GET_POINTER (datalist); |
231 | 0 | G_DATALIST_SET_POINTER (datalist, NULL); |
232 | |
|
233 | 0 | if (data) |
234 | 0 | { |
235 | 0 | G_UNLOCK (g_dataset_global); |
236 | 0 | for (i = 0; i < data->len; i++) |
237 | 0 | { |
238 | 0 | if (data->data[i].data && data->data[i].destroy) |
239 | 0 | data->data[i].destroy (data->data[i].data); |
240 | 0 | } |
241 | 0 | G_LOCK (g_dataset_global); |
242 | |
|
243 | 0 | g_free (data); |
244 | 0 | } |
245 | |
|
246 | 0 | } |
247 | | |
248 | | /** |
249 | | * g_datalist_clear: (skip) |
250 | | * @datalist: a datalist. |
251 | | * |
252 | | * Frees all the data elements of the datalist. |
253 | | * The data elements' destroy functions are called |
254 | | * if they have been set. |
255 | | **/ |
256 | | void |
257 | | g_datalist_clear (GData **datalist) |
258 | 4.32k | { |
259 | 4.32k | GData *data; |
260 | 4.32k | guint i; |
261 | | |
262 | 4.32k | g_return_if_fail (datalist != NULL); |
263 | | |
264 | 4.32k | g_datalist_lock (datalist); |
265 | | |
266 | 4.32k | data = G_DATALIST_GET_POINTER (datalist); |
267 | 4.32k | G_DATALIST_SET_POINTER (datalist, NULL); |
268 | | |
269 | 4.32k | g_datalist_unlock (datalist); |
270 | | |
271 | 4.32k | if (data) |
272 | 0 | { |
273 | 0 | for (i = 0; i < data->len; i++) |
274 | 0 | { |
275 | 0 | if (data->data[i].data && data->data[i].destroy) |
276 | 0 | data->data[i].destroy (data->data[i].data); |
277 | 0 | } |
278 | |
|
279 | 0 | g_free (data); |
280 | 0 | } |
281 | 4.32k | } |
282 | | |
283 | | /* HOLDS: g_dataset_global_lock */ |
284 | | static inline GDataset* |
285 | | g_dataset_lookup (gconstpointer dataset_location) |
286 | 0 | { |
287 | 0 | GDataset *dataset; |
288 | | |
289 | 0 | if (g_dataset_cached && g_dataset_cached->location == dataset_location) |
290 | 0 | return g_dataset_cached; |
291 | | |
292 | 0 | dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location); |
293 | 0 | if (dataset) |
294 | 0 | g_dataset_cached = dataset; |
295 | | |
296 | 0 | return dataset; |
297 | 0 | } |
298 | | |
299 | | /* HOLDS: g_dataset_global_lock */ |
300 | | static void |
301 | | g_dataset_destroy_internal (GDataset *dataset) |
302 | 0 | { |
303 | 0 | gconstpointer dataset_location; |
304 | | |
305 | 0 | dataset_location = dataset->location; |
306 | 0 | while (dataset) |
307 | 0 | { |
308 | 0 | if (G_DATALIST_GET_POINTER(&dataset->datalist) == NULL) |
309 | 0 | { |
310 | 0 | if (dataset == g_dataset_cached) |
311 | 0 | g_dataset_cached = NULL; |
312 | 0 | g_hash_table_remove (g_dataset_location_ht, dataset_location); |
313 | 0 | g_slice_free (GDataset, dataset); |
314 | 0 | break; |
315 | 0 | } |
316 | | |
317 | 0 | g_datalist_clear_i (&dataset->datalist); |
318 | 0 | dataset = g_dataset_lookup (dataset_location); |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | /** |
323 | | * g_dataset_destroy: |
324 | | * @dataset_location: (not nullable): the location identifying the dataset. |
325 | | * |
326 | | * Destroys the dataset, freeing all memory allocated, and calling any |
327 | | * destroy functions set for data elements. |
328 | | */ |
329 | | void |
330 | | g_dataset_destroy (gconstpointer dataset_location) |
331 | 0 | { |
332 | 0 | g_return_if_fail (dataset_location != NULL); |
333 | | |
334 | 0 | G_LOCK (g_dataset_global); |
335 | 0 | if (g_dataset_location_ht) |
336 | 0 | { |
337 | 0 | GDataset *dataset; |
338 | |
|
339 | 0 | dataset = g_dataset_lookup (dataset_location); |
340 | 0 | if (dataset) |
341 | 0 | g_dataset_destroy_internal (dataset); |
342 | 0 | } |
343 | 0 | G_UNLOCK (g_dataset_global); |
344 | 0 | } |
345 | | |
346 | | /* HOLDS: g_dataset_global_lock if dataset != null */ |
347 | | static inline gpointer |
348 | | g_data_set_internal (GData **datalist, |
349 | | GQuark key_id, |
350 | | gpointer new_data, |
351 | | GDestroyNotify new_destroy_func, |
352 | | GDataset *dataset) |
353 | 0 | { |
354 | 0 | GData *d, *old_d; |
355 | 0 | GDataElt old, *data, *data_last, *data_end; |
356 | |
|
357 | 0 | g_datalist_lock (datalist); |
358 | |
|
359 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
360 | |
|
361 | 0 | if (new_data == NULL) /* remove */ |
362 | 0 | { |
363 | 0 | if (d) |
364 | 0 | { |
365 | 0 | data = d->data; |
366 | 0 | data_last = data + d->len - 1; |
367 | 0 | while (data <= data_last) |
368 | 0 | { |
369 | 0 | if (data->key == key_id) |
370 | 0 | { |
371 | 0 | old = *data; |
372 | 0 | if (data != data_last) |
373 | 0 | *data = *data_last; |
374 | 0 | d->len--; |
375 | | |
376 | | /* We don't bother to shrink, but if all data are now gone |
377 | | * we at least free the memory |
378 | | */ |
379 | 0 | if (d->len == 0) |
380 | 0 | { |
381 | 0 | G_DATALIST_SET_POINTER (datalist, NULL); |
382 | 0 | g_free (d); |
383 | | /* datalist may be situated in dataset, so must not be |
384 | | * unlocked after we free it |
385 | | */ |
386 | 0 | g_datalist_unlock (datalist); |
387 | | |
388 | | /* the dataset destruction *must* be done |
389 | | * prior to invocation of the data destroy function |
390 | | */ |
391 | 0 | if (dataset) |
392 | 0 | g_dataset_destroy_internal (dataset); |
393 | 0 | } |
394 | 0 | else |
395 | 0 | { |
396 | 0 | g_datalist_unlock (datalist); |
397 | 0 | } |
398 | | |
399 | | /* We found and removed an old value |
400 | | * the GData struct *must* already be unlinked |
401 | | * when invoking the destroy function. |
402 | | * we use (new_data==NULL && new_destroy_func!=NULL) as |
403 | | * a special hint combination to "steal" |
404 | | * data without destroy notification |
405 | | */ |
406 | 0 | if (old.destroy && !new_destroy_func) |
407 | 0 | { |
408 | 0 | if (dataset) |
409 | 0 | G_UNLOCK (g_dataset_global); |
410 | 0 | old.destroy (old.data); |
411 | 0 | if (dataset) |
412 | 0 | G_LOCK (g_dataset_global); |
413 | 0 | old.data = NULL; |
414 | 0 | } |
415 | |
|
416 | 0 | return old.data; |
417 | 0 | } |
418 | 0 | data++; |
419 | 0 | } |
420 | 0 | } |
421 | 0 | } |
422 | 0 | else |
423 | 0 | { |
424 | 0 | old.data = NULL; |
425 | 0 | if (d) |
426 | 0 | { |
427 | 0 | data = d->data; |
428 | 0 | data_end = data + d->len; |
429 | 0 | while (data < data_end) |
430 | 0 | { |
431 | 0 | if (data->key == key_id) |
432 | 0 | { |
433 | 0 | if (!data->destroy) |
434 | 0 | { |
435 | 0 | data->data = new_data; |
436 | 0 | data->destroy = new_destroy_func; |
437 | 0 | g_datalist_unlock (datalist); |
438 | 0 | } |
439 | 0 | else |
440 | 0 | { |
441 | 0 | old = *data; |
442 | 0 | data->data = new_data; |
443 | 0 | data->destroy = new_destroy_func; |
444 | |
|
445 | 0 | g_datalist_unlock (datalist); |
446 | | |
447 | | /* We found and replaced an old value |
448 | | * the GData struct *must* already be unlinked |
449 | | * when invoking the destroy function. |
450 | | */ |
451 | 0 | if (dataset) |
452 | 0 | G_UNLOCK (g_dataset_global); |
453 | 0 | old.destroy (old.data); |
454 | 0 | if (dataset) |
455 | 0 | G_LOCK (g_dataset_global); |
456 | 0 | } |
457 | 0 | return NULL; |
458 | 0 | } |
459 | 0 | data++; |
460 | 0 | } |
461 | 0 | } |
462 | | |
463 | | /* The key was not found, insert it */ |
464 | 0 | old_d = d; |
465 | 0 | if (d == NULL) |
466 | 0 | { |
467 | 0 | d = g_malloc (sizeof (GData)); |
468 | 0 | d->len = 0; |
469 | 0 | d->alloc = 1; |
470 | 0 | } |
471 | 0 | else if (d->len == d->alloc) |
472 | 0 | { |
473 | 0 | d->alloc = d->alloc * 2; |
474 | 0 | d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt)); |
475 | 0 | } |
476 | 0 | if (old_d != d) |
477 | 0 | G_DATALIST_SET_POINTER (datalist, d); |
478 | |
|
479 | 0 | d->data[d->len].key = key_id; |
480 | 0 | d->data[d->len].data = new_data; |
481 | 0 | d->data[d->len].destroy = new_destroy_func; |
482 | 0 | d->len++; |
483 | 0 | } |
484 | | |
485 | 0 | g_datalist_unlock (datalist); |
486 | |
|
487 | 0 | return NULL; |
488 | |
|
489 | 0 | } |
490 | | |
491 | | static inline void |
492 | | g_data_remove_internal (GData **datalist, |
493 | | GQuark *keys, |
494 | | gsize n_keys) |
495 | 0 | { |
496 | 0 | GData *d; |
497 | |
|
498 | 0 | g_datalist_lock (datalist); |
499 | |
|
500 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
501 | |
|
502 | 0 | if (d) |
503 | 0 | { |
504 | 0 | GDataElt *old, *data, *data_end; |
505 | 0 | gsize found_keys; |
506 | | |
507 | | /* Allocate an array of GDataElt to hold copies of the elements |
508 | | * that are removed from the datalist. Allow enough space for all |
509 | | * the keys; if a key is not found, the corresponding element of |
510 | | * old is not populated, so we initialize them all to NULL to |
511 | | * detect that case. */ |
512 | 0 | old = g_newa0 (GDataElt, n_keys); |
513 | |
|
514 | 0 | data = d->data; |
515 | 0 | data_end = data + d->len; |
516 | 0 | found_keys = 0; |
517 | |
|
518 | 0 | while (data < data_end && found_keys < n_keys) |
519 | 0 | { |
520 | 0 | gboolean remove = FALSE; |
521 | |
|
522 | 0 | for (gsize i = 0; i < n_keys; i++) |
523 | 0 | { |
524 | 0 | if (data->key == keys[i]) |
525 | 0 | { |
526 | 0 | old[i] = *data; |
527 | 0 | remove = TRUE; |
528 | 0 | break; |
529 | 0 | } |
530 | 0 | } |
531 | |
|
532 | 0 | if (remove) |
533 | 0 | { |
534 | 0 | GDataElt *data_last = data_end - 1; |
535 | |
|
536 | 0 | found_keys++; |
537 | |
|
538 | 0 | if (data < data_last) |
539 | 0 | *data = *data_last; |
540 | |
|
541 | 0 | data_end--; |
542 | 0 | d->len--; |
543 | | |
544 | | /* We don't bother to shrink, but if all data are now gone |
545 | | * we at least free the memory |
546 | | */ |
547 | 0 | if (d->len == 0) |
548 | 0 | { |
549 | 0 | G_DATALIST_SET_POINTER (datalist, NULL); |
550 | 0 | g_free (d); |
551 | 0 | break; |
552 | 0 | } |
553 | 0 | } |
554 | 0 | else |
555 | 0 | { |
556 | 0 | data++; |
557 | 0 | } |
558 | 0 | } |
559 | |
|
560 | 0 | if (found_keys > 0) |
561 | 0 | { |
562 | 0 | g_datalist_unlock (datalist); |
563 | |
|
564 | 0 | for (gsize i = 0; i < n_keys; i++) |
565 | 0 | { |
566 | | /* If keys[i] was not found, then old[i].destroy is NULL. |
567 | | * Call old[i].destroy() only if keys[i] was found, and |
568 | | * is associated with a destroy notifier: */ |
569 | 0 | if (old[i].destroy) |
570 | 0 | old[i].destroy (old[i].data); |
571 | 0 | } |
572 | |
|
573 | 0 | return; |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | 0 | g_datalist_unlock (datalist); |
578 | 0 | } |
579 | | |
580 | | /** |
581 | | * g_dataset_id_set_data_full: (skip) |
582 | | * @dataset_location: (not nullable): the location identifying the dataset. |
583 | | * @key_id: the #GQuark id to identify the data element. |
584 | | * @data: the data element. |
585 | | * @destroy_func: the function to call when the data element is |
586 | | * removed. This function will be called with the data |
587 | | * element and can be used to free any memory allocated |
588 | | * for it. |
589 | | * |
590 | | * Sets the data element associated with the given #GQuark id, and also |
591 | | * the function to call when the data element is destroyed. Any |
592 | | * previous data with the same key is removed, and its destroy function |
593 | | * is called. |
594 | | **/ |
595 | | /** |
596 | | * g_dataset_set_data_full: (skip) |
597 | | * @l: the location identifying the dataset. |
598 | | * @k: the string to identify the data element. |
599 | | * @d: the data element. |
600 | | * @f: the function to call when the data element is removed. This |
601 | | * function will be called with the data element and can be used to |
602 | | * free any memory allocated for it. |
603 | | * |
604 | | * Sets the data corresponding to the given string identifier, and the |
605 | | * function to call when the data element is destroyed. |
606 | | **/ |
607 | | /** |
608 | | * g_dataset_id_set_data: |
609 | | * @l: the location identifying the dataset. |
610 | | * @k: the #GQuark id to identify the data element. |
611 | | * @d: the data element. |
612 | | * |
613 | | * Sets the data element associated with the given #GQuark id. Any |
614 | | * previous data with the same key is removed, and its destroy function |
615 | | * is called. |
616 | | **/ |
617 | | /** |
618 | | * g_dataset_set_data: |
619 | | * @l: the location identifying the dataset. |
620 | | * @k: the string to identify the data element. |
621 | | * @d: the data element. |
622 | | * |
623 | | * Sets the data corresponding to the given string identifier. |
624 | | **/ |
625 | | /** |
626 | | * g_dataset_id_remove_data: |
627 | | * @l: the location identifying the dataset. |
628 | | * @k: the #GQuark id identifying the data element. |
629 | | * |
630 | | * Removes a data element from a dataset. The data element's destroy |
631 | | * function is called if it has been set. |
632 | | **/ |
633 | | /** |
634 | | * g_dataset_remove_data: |
635 | | * @l: the location identifying the dataset. |
636 | | * @k: the string identifying the data element. |
637 | | * |
638 | | * Removes a data element corresponding to a string. Its destroy |
639 | | * function is called if it has been set. |
640 | | **/ |
641 | | void |
642 | | g_dataset_id_set_data_full (gconstpointer dataset_location, |
643 | | GQuark key_id, |
644 | | gpointer data, |
645 | | GDestroyNotify destroy_func) |
646 | 0 | { |
647 | 0 | GDataset *dataset; |
648 | | |
649 | 0 | g_return_if_fail (dataset_location != NULL); |
650 | 0 | if (!data) |
651 | 0 | g_return_if_fail (destroy_func == NULL); |
652 | 0 | if (!key_id) |
653 | 0 | { |
654 | 0 | if (data) |
655 | 0 | g_return_if_fail (key_id > 0); |
656 | 0 | else |
657 | 0 | return; |
658 | 0 | } |
659 | | |
660 | 0 | G_LOCK (g_dataset_global); |
661 | 0 | if (!g_dataset_location_ht) |
662 | 0 | g_data_initialize (); |
663 | | |
664 | 0 | dataset = g_dataset_lookup (dataset_location); |
665 | 0 | if (!dataset) |
666 | 0 | { |
667 | 0 | dataset = g_slice_new (GDataset); |
668 | 0 | dataset->location = dataset_location; |
669 | 0 | g_datalist_init (&dataset->datalist); |
670 | 0 | g_hash_table_insert (g_dataset_location_ht, |
671 | 0 | (gpointer) dataset->location, |
672 | 0 | dataset); |
673 | 0 | } |
674 | | |
675 | 0 | g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset); |
676 | 0 | G_UNLOCK (g_dataset_global); |
677 | 0 | } |
678 | | |
679 | | /** |
680 | | * g_datalist_id_set_data_full: (skip) |
681 | | * @datalist: a datalist. |
682 | | * @key_id: the #GQuark to identify the data element. |
683 | | * @data: (nullable): the data element or %NULL to remove any previous element |
684 | | * corresponding to @key_id. |
685 | | * @destroy_func: (nullable): the function to call when the data element is |
686 | | * removed. This function will be called with the data |
687 | | * element and can be used to free any memory allocated |
688 | | * for it. If @data is %NULL, then @destroy_func must |
689 | | * also be %NULL. |
690 | | * |
691 | | * Sets the data corresponding to the given #GQuark id, and the |
692 | | * function to be called when the element is removed from the datalist. |
693 | | * Any previous data with the same key is removed, and its destroy |
694 | | * function is called. |
695 | | **/ |
696 | | /** |
697 | | * g_datalist_set_data_full: (skip) |
698 | | * @dl: a datalist. |
699 | | * @k: the string to identify the data element. |
700 | | * @d: (nullable): the data element, or %NULL to remove any previous element |
701 | | * corresponding to @k. |
702 | | * @f: (nullable): the function to call when the data element is removed. |
703 | | * This function will be called with the data element and can be used to |
704 | | * free any memory allocated for it. If @d is %NULL, then @f must |
705 | | * also be %NULL. |
706 | | * |
707 | | * Sets the data element corresponding to the given string identifier, |
708 | | * and the function to be called when the data element is removed. |
709 | | **/ |
710 | | /** |
711 | | * g_datalist_id_set_data: |
712 | | * @dl: a datalist. |
713 | | * @q: the #GQuark to identify the data element. |
714 | | * @d: (nullable): the data element, or %NULL to remove any previous element |
715 | | * corresponding to @q. |
716 | | * |
717 | | * Sets the data corresponding to the given #GQuark id. Any previous |
718 | | * data with the same key is removed, and its destroy function is |
719 | | * called. |
720 | | **/ |
721 | | /** |
722 | | * g_datalist_set_data: |
723 | | * @dl: a datalist. |
724 | | * @k: the string to identify the data element. |
725 | | * @d: (nullable): the data element, or %NULL to remove any previous element |
726 | | * corresponding to @k. |
727 | | * |
728 | | * Sets the data element corresponding to the given string identifier. |
729 | | **/ |
730 | | /** |
731 | | * g_datalist_id_remove_data: |
732 | | * @dl: a datalist. |
733 | | * @q: the #GQuark identifying the data element. |
734 | | * |
735 | | * Removes an element, using its #GQuark identifier. |
736 | | **/ |
737 | | /** |
738 | | * g_datalist_remove_data: |
739 | | * @dl: a datalist. |
740 | | * @k: the string identifying the data element. |
741 | | * |
742 | | * Removes an element using its string identifier. The data element's |
743 | | * destroy function is called if it has been set. |
744 | | **/ |
745 | | void |
746 | | g_datalist_id_set_data_full (GData **datalist, |
747 | | GQuark key_id, |
748 | | gpointer data, |
749 | | GDestroyNotify destroy_func) |
750 | 0 | { |
751 | 0 | g_return_if_fail (datalist != NULL); |
752 | 0 | if (!data) |
753 | 0 | g_return_if_fail (destroy_func == NULL); |
754 | 0 | if (!key_id) |
755 | 0 | { |
756 | 0 | if (data) |
757 | 0 | g_return_if_fail (key_id > 0); |
758 | 0 | else |
759 | 0 | return; |
760 | 0 | } |
761 | | |
762 | 0 | g_data_set_internal (datalist, key_id, data, destroy_func, NULL); |
763 | 0 | } |
764 | | |
765 | | /** |
766 | | * g_datalist_id_remove_multiple: |
767 | | * @datalist: a datalist |
768 | | * @keys: (array length=n_keys): keys to remove |
769 | | * @n_keys: length of @keys, must be <= 16 |
770 | | * |
771 | | * Removes multiple keys from a datalist. |
772 | | * |
773 | | * This is more efficient than calling g_datalist_id_remove_data() |
774 | | * multiple times in a row. |
775 | | * |
776 | | * Since: 2.74 |
777 | | */ |
778 | | void |
779 | | g_datalist_id_remove_multiple (GData **datalist, |
780 | | GQuark *keys, |
781 | | gsize n_keys) |
782 | 0 | { |
783 | 0 | g_return_if_fail (n_keys <= 16); |
784 | | |
785 | 0 | g_data_remove_internal (datalist, keys, n_keys); |
786 | 0 | } |
787 | | |
788 | | /** |
789 | | * g_dataset_id_remove_no_notify: (skip) |
790 | | * @dataset_location: (not nullable): the location identifying the dataset. |
791 | | * @key_id: the #GQuark ID identifying the data element. |
792 | | * |
793 | | * Removes an element, without calling its destroy notification |
794 | | * function. |
795 | | * |
796 | | * Returns: (nullable): the data previously stored at @key_id, |
797 | | * or %NULL if none. |
798 | | **/ |
799 | | /** |
800 | | * g_dataset_remove_no_notify: (skip) |
801 | | * @l: the location identifying the dataset. |
802 | | * @k: the string identifying the data element. |
803 | | * |
804 | | * Removes an element, without calling its destroy notifier. |
805 | | **/ |
806 | | gpointer |
807 | | g_dataset_id_remove_no_notify (gconstpointer dataset_location, |
808 | | GQuark key_id) |
809 | 0 | { |
810 | 0 | gpointer ret_data = NULL; |
811 | |
|
812 | 0 | g_return_val_if_fail (dataset_location != NULL, NULL); |
813 | | |
814 | 0 | G_LOCK (g_dataset_global); |
815 | 0 | if (key_id && g_dataset_location_ht) |
816 | 0 | { |
817 | 0 | GDataset *dataset; |
818 | | |
819 | 0 | dataset = g_dataset_lookup (dataset_location); |
820 | 0 | if (dataset) |
821 | 0 | ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset); |
822 | 0 | } |
823 | 0 | G_UNLOCK (g_dataset_global); |
824 | |
|
825 | 0 | return ret_data; |
826 | 0 | } |
827 | | |
828 | | /** |
829 | | * g_datalist_id_remove_no_notify: (skip) |
830 | | * @datalist: a datalist. |
831 | | * @key_id: the #GQuark identifying a data element. |
832 | | * |
833 | | * Removes an element, without calling its destroy notification |
834 | | * function. |
835 | | * |
836 | | * Returns: (nullable): the data previously stored at @key_id, |
837 | | * or %NULL if none. |
838 | | **/ |
839 | | /** |
840 | | * g_datalist_remove_no_notify: (skip) |
841 | | * @dl: a datalist. |
842 | | * @k: the string identifying the data element. |
843 | | * |
844 | | * Removes an element, without calling its destroy notifier. |
845 | | **/ |
846 | | gpointer |
847 | | g_datalist_id_remove_no_notify (GData **datalist, |
848 | | GQuark key_id) |
849 | 0 | { |
850 | 0 | gpointer ret_data = NULL; |
851 | |
|
852 | 0 | g_return_val_if_fail (datalist != NULL, NULL); |
853 | | |
854 | 0 | if (key_id) |
855 | 0 | ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL); |
856 | |
|
857 | 0 | return ret_data; |
858 | 0 | } |
859 | | |
860 | | /** |
861 | | * g_dataset_id_get_data: |
862 | | * @dataset_location: (not nullable): the location identifying the dataset. |
863 | | * @key_id: the #GQuark id to identify the data element. |
864 | | * |
865 | | * Gets the data element corresponding to a #GQuark. |
866 | | * |
867 | | * Returns: (transfer none) (nullable): the data element corresponding to |
868 | | * the #GQuark, or %NULL if it is not found. |
869 | | **/ |
870 | | /** |
871 | | * g_dataset_get_data: |
872 | | * @l: the location identifying the dataset. |
873 | | * @k: the string identifying the data element. |
874 | | * |
875 | | * Gets the data element corresponding to a string. |
876 | | * |
877 | | * Returns: (transfer none) (nullable): the data element corresponding to |
878 | | * the string, or %NULL if it is not found. |
879 | | **/ |
880 | | gpointer |
881 | | g_dataset_id_get_data (gconstpointer dataset_location, |
882 | | GQuark key_id) |
883 | 0 | { |
884 | 0 | gpointer retval = NULL; |
885 | |
|
886 | 0 | g_return_val_if_fail (dataset_location != NULL, NULL); |
887 | | |
888 | 0 | G_LOCK (g_dataset_global); |
889 | 0 | if (key_id && g_dataset_location_ht) |
890 | 0 | { |
891 | 0 | GDataset *dataset; |
892 | | |
893 | 0 | dataset = g_dataset_lookup (dataset_location); |
894 | 0 | if (dataset) |
895 | 0 | retval = g_datalist_id_get_data (&dataset->datalist, key_id); |
896 | 0 | } |
897 | 0 | G_UNLOCK (g_dataset_global); |
898 | | |
899 | 0 | return retval; |
900 | 0 | } |
901 | | |
902 | | /** |
903 | | * g_datalist_id_get_data: |
904 | | * @datalist: a datalist. |
905 | | * @key_id: the #GQuark identifying a data element. |
906 | | * |
907 | | * Retrieves the data element corresponding to @key_id. |
908 | | * |
909 | | * Returns: (transfer none) (nullable): the data element, or %NULL if |
910 | | * it is not found. |
911 | | */ |
912 | | gpointer |
913 | | g_datalist_id_get_data (GData **datalist, |
914 | | GQuark key_id) |
915 | 0 | { |
916 | 0 | return g_datalist_id_dup_data (datalist, key_id, NULL, NULL); |
917 | 0 | } |
918 | | |
919 | | /** |
920 | | * GDuplicateFunc: |
921 | | * @data: the data to duplicate |
922 | | * @user_data: (closure): user data that was specified in |
923 | | * g_datalist_id_dup_data() |
924 | | * |
925 | | * The type of functions that are used to 'duplicate' an object. |
926 | | * What this means depends on the context, it could just be |
927 | | * incrementing the reference count, if @data is a ref-counted |
928 | | * object. |
929 | | * |
930 | | * Returns: a duplicate of data |
931 | | */ |
932 | | |
933 | | /** |
934 | | * g_datalist_id_dup_data: (skip) |
935 | | * @datalist: location of a datalist |
936 | | * @key_id: the #GQuark identifying a data element |
937 | | * @dup_func: (nullable) (scope call): function to duplicate the old value |
938 | | * @user_data: (closure): passed as user_data to @dup_func |
939 | | * |
940 | | * This is a variant of g_datalist_id_get_data() which |
941 | | * returns a 'duplicate' of the value. @dup_func defines the |
942 | | * meaning of 'duplicate' in this context, it could e.g. |
943 | | * take a reference on a ref-counted object. |
944 | | * |
945 | | * If the @key_id is not set in the datalist then @dup_func |
946 | | * will be called with a %NULL argument. |
947 | | * |
948 | | * Note that @dup_func is called while the datalist is locked, so it |
949 | | * is not allowed to read or modify the datalist. |
950 | | * |
951 | | * This function can be useful to avoid races when multiple |
952 | | * threads are using the same datalist and the same key. |
953 | | * |
954 | | * Returns: (nullable): the result of calling @dup_func on the value |
955 | | * associated with @key_id in @datalist, or %NULL if not set. |
956 | | * If @dup_func is %NULL, the value is returned unmodified. |
957 | | * |
958 | | * Since: 2.34 |
959 | | */ |
960 | | gpointer |
961 | | g_datalist_id_dup_data (GData **datalist, |
962 | | GQuark key_id, |
963 | | GDuplicateFunc dup_func, |
964 | | gpointer user_data) |
965 | 0 | { |
966 | 0 | gpointer val = NULL; |
967 | 0 | gpointer retval = NULL; |
968 | 0 | GData *d; |
969 | 0 | GDataElt *data, *data_end; |
970 | |
|
971 | 0 | g_datalist_lock (datalist); |
972 | |
|
973 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
974 | 0 | if (d) |
975 | 0 | { |
976 | 0 | data = d->data; |
977 | 0 | data_end = data + d->len; |
978 | 0 | do |
979 | 0 | { |
980 | 0 | if (data->key == key_id) |
981 | 0 | { |
982 | 0 | val = data->data; |
983 | 0 | break; |
984 | 0 | } |
985 | 0 | data++; |
986 | 0 | } |
987 | 0 | while (data < data_end); |
988 | 0 | } |
989 | | |
990 | 0 | if (dup_func) |
991 | 0 | retval = dup_func (val, user_data); |
992 | 0 | else |
993 | 0 | retval = val; |
994 | |
|
995 | 0 | g_datalist_unlock (datalist); |
996 | |
|
997 | 0 | return retval; |
998 | 0 | } |
999 | | |
1000 | | /** |
1001 | | * g_datalist_id_replace_data: (skip) |
1002 | | * @datalist: location of a datalist |
1003 | | * @key_id: the #GQuark identifying a data element |
1004 | | * @oldval: (nullable): the old value to compare against |
1005 | | * @newval: (nullable): the new value to replace it with |
1006 | | * @destroy: (nullable): destroy notify for the new value |
1007 | | * @old_destroy: (out) (optional): destroy notify for the existing value |
1008 | | * |
1009 | | * Compares the member that is associated with @key_id in |
1010 | | * @datalist to @oldval, and if they are the same, replace |
1011 | | * @oldval with @newval. |
1012 | | * |
1013 | | * This is like a typical atomic compare-and-exchange |
1014 | | * operation, for a member of @datalist. |
1015 | | * |
1016 | | * If the previous value was replaced then ownership of the |
1017 | | * old value (@oldval) is passed to the caller, including |
1018 | | * the registered destroy notify for it (passed out in @old_destroy). |
1019 | | * Its up to the caller to free this as they wish, which may |
1020 | | * or may not include using @old_destroy as sometimes replacement |
1021 | | * should not destroy the object in the normal way. |
1022 | | * |
1023 | | * Returns: %TRUE if the existing value for @key_id was replaced |
1024 | | * by @newval, %FALSE otherwise. |
1025 | | * |
1026 | | * Since: 2.34 |
1027 | | */ |
1028 | | gboolean |
1029 | | g_datalist_id_replace_data (GData **datalist, |
1030 | | GQuark key_id, |
1031 | | gpointer oldval, |
1032 | | gpointer newval, |
1033 | | GDestroyNotify destroy, |
1034 | | GDestroyNotify *old_destroy) |
1035 | 0 | { |
1036 | 0 | gpointer val = NULL; |
1037 | 0 | GData *d; |
1038 | 0 | GDataElt *data, *data_end; |
1039 | |
|
1040 | 0 | g_return_val_if_fail (datalist != NULL, FALSE); |
1041 | 0 | g_return_val_if_fail (key_id != 0, FALSE); |
1042 | | |
1043 | 0 | if (old_destroy) |
1044 | 0 | *old_destroy = NULL; |
1045 | |
|
1046 | 0 | g_datalist_lock (datalist); |
1047 | |
|
1048 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
1049 | 0 | if (d) |
1050 | 0 | { |
1051 | 0 | data = d->data; |
1052 | 0 | data_end = data + d->len - 1; |
1053 | 0 | while (data <= data_end) |
1054 | 0 | { |
1055 | 0 | if (data->key == key_id) |
1056 | 0 | { |
1057 | 0 | val = data->data; |
1058 | 0 | if (val == oldval) |
1059 | 0 | { |
1060 | 0 | if (old_destroy) |
1061 | 0 | *old_destroy = data->destroy; |
1062 | 0 | if (newval != NULL) |
1063 | 0 | { |
1064 | 0 | data->data = newval; |
1065 | 0 | data->destroy = destroy; |
1066 | 0 | } |
1067 | 0 | else |
1068 | 0 | { |
1069 | 0 | if (data != data_end) |
1070 | 0 | *data = *data_end; |
1071 | 0 | d->len--; |
1072 | | |
1073 | | /* We don't bother to shrink, but if all data are now gone |
1074 | | * we at least free the memory |
1075 | | */ |
1076 | 0 | if (d->len == 0) |
1077 | 0 | { |
1078 | 0 | G_DATALIST_SET_POINTER (datalist, NULL); |
1079 | 0 | g_free (d); |
1080 | 0 | } |
1081 | 0 | } |
1082 | 0 | } |
1083 | 0 | break; |
1084 | 0 | } |
1085 | 0 | data++; |
1086 | 0 | } |
1087 | 0 | } |
1088 | |
|
1089 | 0 | if (val == NULL && oldval == NULL && newval != NULL) |
1090 | 0 | { |
1091 | 0 | GData *old_d; |
1092 | | |
1093 | | /* insert newval */ |
1094 | 0 | old_d = d; |
1095 | 0 | if (d == NULL) |
1096 | 0 | { |
1097 | 0 | d = g_malloc (sizeof (GData)); |
1098 | 0 | d->len = 0; |
1099 | 0 | d->alloc = 1; |
1100 | 0 | } |
1101 | 0 | else if (d->len == d->alloc) |
1102 | 0 | { |
1103 | 0 | d->alloc = d->alloc * 2; |
1104 | 0 | d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt)); |
1105 | 0 | } |
1106 | 0 | if (old_d != d) |
1107 | 0 | G_DATALIST_SET_POINTER (datalist, d); |
1108 | |
|
1109 | 0 | d->data[d->len].key = key_id; |
1110 | 0 | d->data[d->len].data = newval; |
1111 | 0 | d->data[d->len].destroy = destroy; |
1112 | 0 | d->len++; |
1113 | 0 | } |
1114 | |
|
1115 | 0 | g_datalist_unlock (datalist); |
1116 | |
|
1117 | 0 | return val == oldval; |
1118 | 0 | } |
1119 | | |
1120 | | /** |
1121 | | * g_datalist_get_data: |
1122 | | * @datalist: a datalist. |
1123 | | * @key: the string identifying a data element. |
1124 | | * |
1125 | | * Gets a data element, using its string identifier. This is slower than |
1126 | | * g_datalist_id_get_data() because it compares strings. |
1127 | | * |
1128 | | * Returns: (transfer none) (nullable): the data element, or %NULL if it |
1129 | | * is not found. |
1130 | | **/ |
1131 | | gpointer |
1132 | | g_datalist_get_data (GData **datalist, |
1133 | | const gchar *key) |
1134 | 0 | { |
1135 | 0 | gpointer res = NULL; |
1136 | 0 | GData *d; |
1137 | 0 | GDataElt *data, *data_end; |
1138 | |
|
1139 | 0 | g_return_val_if_fail (datalist != NULL, NULL); |
1140 | | |
1141 | 0 | g_datalist_lock (datalist); |
1142 | |
|
1143 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
1144 | 0 | if (d) |
1145 | 0 | { |
1146 | 0 | data = d->data; |
1147 | 0 | data_end = data + d->len; |
1148 | 0 | while (data < data_end) |
1149 | 0 | { |
1150 | 0 | if (g_strcmp0 (g_quark_to_string (data->key), key) == 0) |
1151 | 0 | { |
1152 | 0 | res = data->data; |
1153 | 0 | break; |
1154 | 0 | } |
1155 | 0 | data++; |
1156 | 0 | } |
1157 | 0 | } |
1158 | |
|
1159 | 0 | g_datalist_unlock (datalist); |
1160 | |
|
1161 | 0 | return res; |
1162 | 0 | } |
1163 | | |
1164 | | /** |
1165 | | * GDataForeachFunc: |
1166 | | * @key_id: the #GQuark id to identifying the data element. |
1167 | | * @data: the data element. |
1168 | | * @user_data: (closure): user data passed to g_dataset_foreach(). |
1169 | | * |
1170 | | * Specifies the type of function passed to g_dataset_foreach(). It is |
1171 | | * called with each #GQuark id and associated data element, together |
1172 | | * with the @user_data parameter supplied to g_dataset_foreach(). |
1173 | | **/ |
1174 | | |
1175 | | /** |
1176 | | * g_dataset_foreach: |
1177 | | * @dataset_location: (not nullable): the location identifying the dataset. |
1178 | | * @func: (scope call): the function to call for each data element. |
1179 | | * @user_data: (closure): user data to pass to the function. |
1180 | | * |
1181 | | * Calls the given function for each data element which is associated |
1182 | | * with the given location. Note that this function is NOT thread-safe. |
1183 | | * So unless @dataset_location can be protected from any modifications |
1184 | | * during invocation of this function, it should not be called. |
1185 | | * |
1186 | | * @func can make changes to the dataset, but the iteration will not |
1187 | | * reflect changes made during the g_dataset_foreach() call, other |
1188 | | * than skipping over elements that are removed. |
1189 | | **/ |
1190 | | void |
1191 | | g_dataset_foreach (gconstpointer dataset_location, |
1192 | | GDataForeachFunc func, |
1193 | | gpointer user_data) |
1194 | 0 | { |
1195 | 0 | GDataset *dataset; |
1196 | | |
1197 | 0 | g_return_if_fail (dataset_location != NULL); |
1198 | 0 | g_return_if_fail (func != NULL); |
1199 | | |
1200 | 0 | G_LOCK (g_dataset_global); |
1201 | 0 | if (g_dataset_location_ht) |
1202 | 0 | { |
1203 | 0 | dataset = g_dataset_lookup (dataset_location); |
1204 | 0 | G_UNLOCK (g_dataset_global); |
1205 | 0 | if (dataset) |
1206 | 0 | g_datalist_foreach (&dataset->datalist, func, user_data); |
1207 | 0 | } |
1208 | 0 | else |
1209 | 0 | { |
1210 | 0 | G_UNLOCK (g_dataset_global); |
1211 | 0 | } |
1212 | 0 | } |
1213 | | |
1214 | | /** |
1215 | | * g_datalist_foreach: |
1216 | | * @datalist: a datalist. |
1217 | | * @func: (scope call): the function to call for each data element. |
1218 | | * @user_data: (closure): user data to pass to the function. |
1219 | | * |
1220 | | * Calls the given function for each data element of the datalist. The |
1221 | | * function is called with each data element's #GQuark id and data, |
1222 | | * together with the given @user_data parameter. Note that this |
1223 | | * function is NOT thread-safe. So unless @datalist can be protected |
1224 | | * from any modifications during invocation of this function, it should |
1225 | | * not be called. |
1226 | | * |
1227 | | * @func can make changes to @datalist, but the iteration will not |
1228 | | * reflect changes made during the g_datalist_foreach() call, other |
1229 | | * than skipping over elements that are removed. |
1230 | | **/ |
1231 | | void |
1232 | | g_datalist_foreach (GData **datalist, |
1233 | | GDataForeachFunc func, |
1234 | | gpointer user_data) |
1235 | 0 | { |
1236 | 0 | GData *d; |
1237 | 0 | guint i, j, len; |
1238 | 0 | GQuark *keys; |
1239 | |
|
1240 | 0 | g_return_if_fail (datalist != NULL); |
1241 | 0 | g_return_if_fail (func != NULL); |
1242 | | |
1243 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
1244 | 0 | if (d == NULL) |
1245 | 0 | return; |
1246 | | |
1247 | | /* We make a copy of the keys so that we can handle it changing |
1248 | | in the callback */ |
1249 | 0 | len = d->len; |
1250 | 0 | keys = g_new (GQuark, len); |
1251 | 0 | for (i = 0; i < len; i++) |
1252 | 0 | keys[i] = d->data[i].key; |
1253 | | |
1254 | 0 | for (i = 0; i < len; i++) |
1255 | 0 | { |
1256 | | /* A previous callback might have removed a later item, so always check that |
1257 | | it still exists before calling */ |
1258 | 0 | d = G_DATALIST_GET_POINTER (datalist); |
1259 | | |
1260 | 0 | if (d == NULL) |
1261 | 0 | break; |
1262 | 0 | for (j = 0; j < d->len; j++) |
1263 | 0 | { |
1264 | 0 | if (d->data[j].key == keys[i]) { |
1265 | 0 | func (d->data[i].key, d->data[i].data, user_data); |
1266 | 0 | break; |
1267 | 0 | } |
1268 | 0 | } |
1269 | 0 | } |
1270 | 0 | g_free (keys); |
1271 | 0 | } |
1272 | | |
1273 | | /** |
1274 | | * g_datalist_init: (skip) |
1275 | | * @datalist: a pointer to a pointer to a datalist. |
1276 | | * |
1277 | | * Resets the datalist to %NULL. It does not free any memory or call |
1278 | | * any destroy functions. |
1279 | | **/ |
1280 | | void |
1281 | | g_datalist_init (GData **datalist) |
1282 | 4.32k | { |
1283 | 4.32k | g_return_if_fail (datalist != NULL); |
1284 | | |
1285 | 4.32k | g_atomic_pointer_set (datalist, NULL); |
1286 | 4.32k | } |
1287 | | |
1288 | | /** |
1289 | | * g_datalist_set_flags: |
1290 | | * @datalist: pointer to the location that holds a list |
1291 | | * @flags: the flags to turn on. The values of the flags are |
1292 | | * restricted by %G_DATALIST_FLAGS_MASK (currently |
1293 | | * 3; giving two possible boolean flags). |
1294 | | * A value for @flags that doesn't fit within the mask is |
1295 | | * an error. |
1296 | | * |
1297 | | * Turns on flag values for a data list. This function is used |
1298 | | * to keep a small number of boolean flags in an object with |
1299 | | * a data list without using any additional space. It is |
1300 | | * not generally useful except in circumstances where space |
1301 | | * is very tight. (It is used in the base #GObject type, for |
1302 | | * example.) |
1303 | | * |
1304 | | * Since: 2.8 |
1305 | | **/ |
1306 | | void |
1307 | | g_datalist_set_flags (GData **datalist, |
1308 | | guint flags) |
1309 | 0 | { |
1310 | 0 | g_return_if_fail (datalist != NULL); |
1311 | 0 | g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0); |
1312 | | |
1313 | 0 | g_atomic_pointer_or (datalist, (gsize)flags); |
1314 | 0 | } |
1315 | | |
1316 | | /** |
1317 | | * g_datalist_unset_flags: |
1318 | | * @datalist: pointer to the location that holds a list |
1319 | | * @flags: the flags to turn off. The values of the flags are |
1320 | | * restricted by %G_DATALIST_FLAGS_MASK (currently |
1321 | | * 3: giving two possible boolean flags). |
1322 | | * A value for @flags that doesn't fit within the mask is |
1323 | | * an error. |
1324 | | * |
1325 | | * Turns off flag values for a data list. See g_datalist_unset_flags() |
1326 | | * |
1327 | | * Since: 2.8 |
1328 | | **/ |
1329 | | void |
1330 | | g_datalist_unset_flags (GData **datalist, |
1331 | | guint flags) |
1332 | 0 | { |
1333 | 0 | g_return_if_fail (datalist != NULL); |
1334 | 0 | g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0); |
1335 | | |
1336 | 0 | g_atomic_pointer_and (datalist, ~(gsize)flags); |
1337 | 0 | } |
1338 | | |
1339 | | /** |
1340 | | * g_datalist_get_flags: |
1341 | | * @datalist: pointer to the location that holds a list |
1342 | | * |
1343 | | * Gets flags values packed in together with the datalist. |
1344 | | * See g_datalist_set_flags(). |
1345 | | * |
1346 | | * Returns: the flags of the datalist |
1347 | | * |
1348 | | * Since: 2.8 |
1349 | | **/ |
1350 | | guint |
1351 | | g_datalist_get_flags (GData **datalist) |
1352 | 0 | { |
1353 | 0 | g_return_val_if_fail (datalist != NULL, 0); |
1354 | | |
1355 | 0 | return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */ |
1356 | 0 | } |
1357 | | |
1358 | | /* HOLDS: g_dataset_global_lock */ |
1359 | | static void |
1360 | | g_data_initialize (void) |
1361 | 0 | { |
1362 | 0 | g_return_if_fail (g_dataset_location_ht == NULL); |
1363 | | |
1364 | 0 | g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL); |
1365 | 0 | g_dataset_cached = NULL; |
1366 | 0 | } |