/* HOLDS: g_dataset_global_lock */ static inline void g_datalist_clear_i (GData **datalist) { register GData *list; /* unlink *all* items before walking their destructors */ list = G_DATALIST_GET_POINTER (datalist); G_DATALIST_SET_POINTER (datalist, NULL); while (list) { register GData *prev; prev = list; list = prev->next; if (prev->destroy_func) { G_UNLOCK (g_dataset_global); prev->destroy_func (prev->data); G_LOCK (g_dataset_global); } g_slice_free (GData, prev); } }
/** * g_datalist_clear: (skip) * @datalist: a datalist. * * Frees all the data elements of the datalist. * The data elements' destroy functions are called * if they have been set. **/ void g_datalist_clear (GData **datalist) { GData *data; gint i; g_return_if_fail (datalist != NULL); g_datalist_lock (datalist); data = G_DATALIST_GET_POINTER (datalist); G_DATALIST_SET_POINTER (datalist, NULL); g_datalist_unlock (datalist); if (data) { for (i = 0; i < data->len; i++) { if (data->data[i].data && data->data[i].destroy) data->data[i].destroy (data->data[i].data); } g_free (data); } }
/* Called with the datalist lock held, or the dataset global * lock for dataset lists */ static void g_datalist_clear_i (GData **datalist) { GData *data; gint i; data = G_DATALIST_GET_POINTER (datalist); G_DATALIST_SET_POINTER (datalist, NULL); if (data) { G_UNLOCK (g_dataset_global); for (i = 0; i < data->len; i++) { if (data->data[i].data && data->data[i].destroy) data->data[i].destroy (data->data[i].data); } G_LOCK (g_dataset_global); g_free (data); } }
/* HOLDS: g_dataset_global_lock */ static inline gpointer g_data_set_internal (GData **datalist, GQuark key_id, gpointer data, GDestroyNotify destroy_func, GDataset *dataset) { register GData *list; list = G_DATALIST_GET_POINTER (datalist); if (!data) { register GData *prev; prev = NULL; while (list) { if (list->id == key_id) { gpointer ret_data = NULL; if (prev) prev->next = list->next; else { G_DATALIST_SET_POINTER (datalist, list->next); /* the dataset destruction *must* be done * prior to invocation of the data destroy function */ if (!list->next && dataset) g_dataset_destroy_internal (dataset); } /* the GData struct *must* already be unlinked * when invoking the destroy function. * we use (data==NULL && destroy_func!=NULL) as * a special hint combination to "steal" * data without destroy notification */ if (list->destroy_func && !destroy_func) { G_UNLOCK (g_dataset_global); list->destroy_func (list->data); G_LOCK (g_dataset_global); } else ret_data = list->data; g_slice_free (GData, list); return ret_data; } prev = list; list = list->next; } } else { while (list) { if (list->id == key_id) { if (!list->destroy_func) { list->data = data; list->destroy_func = destroy_func; } else { register GDestroyNotify dfunc; register gpointer ddata; dfunc = list->destroy_func; ddata = list->data; list->data = data; list->destroy_func = destroy_func; /* we need to have updated all structures prior to * invocation of the destroy function */ G_UNLOCK (g_dataset_global); dfunc (ddata); G_LOCK (g_dataset_global); } return NULL; } list = list->next; } list = g_slice_new (GData); list->next = G_DATALIST_GET_POINTER (datalist); list->id = key_id; list->data = data; list->destroy_func = destroy_func; G_DATALIST_SET_POINTER (datalist, list); } return NULL; }
/** * g_datalist_id_replace_data: (skip) * @datalist: location of a datalist * @key_id: the #GQuark identifying a data element * @oldval: (nullable): the old value to compare against * @newval: (nullable): the new value to replace it with * @destroy: (nullable): destroy notify for the new value * @old_destroy: (out) (optional): destroy notify for the existing value * * Compares the member that is associated with @key_id in * @datalist to @oldval, and if they are the same, replace * @oldval with @newval. * * This is like a typical atomic compare-and-exchange * operation, for a member of @datalist. * * If the previous value was replaced then ownership of the * old value (@oldval) is passed to the caller, including * the registered destroy notify for it (passed out in @old_destroy). * Its up to the caller to free this as he wishes, which may * or may not include using @old_destroy as sometimes replacement * should not destroy the object in the normal way. * * Returns: %TRUE if the existing value for @key_id was replaced * by @newval, %FALSE otherwise. * * Since: 2.34 */ gboolean g_datalist_id_replace_data (GData **datalist, GQuark key_id, gpointer oldval, gpointer newval, GDestroyNotify destroy, GDestroyNotify *old_destroy) { gpointer val = NULL; GData *d; GDataElt *data, *data_end; g_return_val_if_fail (datalist != NULL, FALSE); g_return_val_if_fail (key_id != 0, FALSE); if (old_destroy) *old_destroy = NULL; g_datalist_lock (datalist); d = G_DATALIST_GET_POINTER (datalist); if (d) { data = d->data; data_end = data + d->len - 1; while (data <= data_end) { if (data->key == key_id) { val = data->data; if (val == oldval) { if (old_destroy) *old_destroy = data->destroy; if (newval != NULL) { data->data = newval; data->destroy = destroy; } else { if (data != data_end) *data = *data_end; d->len--; /* We don't bother to shrink, but if all data are now gone * we at least free the memory */ if (d->len == 0) { G_DATALIST_SET_POINTER (datalist, NULL); g_free (d); } } } break; } data++; } } if (val == NULL && oldval == NULL && newval != NULL) { GData *old_d; /* insert newval */ old_d = d; if (d == NULL) { d = g_malloc (sizeof (GData)); d->len = 0; d->alloc = 1; } else if (d->len == d->alloc) { d->alloc = d->alloc * 2; d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt)); } if (old_d != d) G_DATALIST_SET_POINTER (datalist, d); d->data[d->len].key = key_id; d->data[d->len].data = newval; d->data[d->len].destroy = destroy; d->len++; } g_datalist_unlock (datalist); return val == oldval; }
/* HOLDS: g_dataset_global_lock if dataset != null */ static inline gpointer g_data_set_internal (GData **datalist, GQuark key_id, gpointer new_data, GDestroyNotify new_destroy_func, GDataset *dataset) { GData *d, *old_d; GDataElt old, *data, *data_last, *data_end; g_datalist_lock (datalist); d = G_DATALIST_GET_POINTER (datalist); if (new_data == NULL) /* remove */ { if (d) { data = d->data; data_last = data + d->len - 1; while (data <= data_last) { if (data->key == key_id) { old = *data; if (data != data_last) *data = *data_last; d->len--; /* We don't bother to shrink, but if all data are now gone * we at least free the memory */ if (d->len == 0) { G_DATALIST_SET_POINTER (datalist, NULL); g_free (d); /* datalist may be situated in dataset, so must not be * unlocked after we free it */ g_datalist_unlock (datalist); /* the dataset destruction *must* be done * prior to invocation of the data destroy function */ if (dataset) g_dataset_destroy_internal (dataset); } else { g_datalist_unlock (datalist); } /* We found and removed an old value * the GData struct *must* already be unlinked * when invoking the destroy function. * we use (new_data==NULL && new_destroy_func!=NULL) as * a special hint combination to "steal" * data without destroy notification */ if (old.destroy && !new_destroy_func) { if (dataset) G_UNLOCK (g_dataset_global); old.destroy (old.data); if (dataset) G_LOCK (g_dataset_global); old.data = NULL; } return old.data; } data++; } } } else { old.data = NULL; if (d) { data = d->data; data_end = data + d->len; while (data < data_end) { if (data->key == key_id) { if (!data->destroy) { data->data = new_data; data->destroy = new_destroy_func; g_datalist_unlock (datalist); } else { old = *data; data->data = new_data; data->destroy = new_destroy_func; g_datalist_unlock (datalist); /* We found and replaced an old value * the GData struct *must* already be unlinked * when invoking the destroy function. */ if (dataset) G_UNLOCK (g_dataset_global); old.destroy (old.data); if (dataset) G_LOCK (g_dataset_global); } return NULL; } data++; } } /* The key was not found, insert it */ old_d = d; if (d == NULL) { d = g_malloc (sizeof (GData)); d->len = 0; d->alloc = 1; } else if (d->len == d->alloc) { d->alloc = d->alloc * 2; d = g_realloc (d, sizeof (GData) + (d->alloc - 1) * sizeof (GDataElt)); } if (old_d != d) G_DATALIST_SET_POINTER (datalist, d); d->data[d->len].key = key_id; d->data[d->len].data = new_data; d->data[d->len].destroy = new_destroy_func; d->len++; } g_datalist_unlock (datalist); return NULL; }