/** * 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); } }
/** * g_datalist_get_data: * @datalist: a datalist. * @key: the string identifying a data element. * * Gets a data element, using its string identifier. This is slower than * g_datalist_id_get_data() because it compares strings. * * Returns: (transfer none) (nullable): the data element, or %NULL if it * is not found. **/ gpointer g_datalist_get_data (GData **datalist, const gchar *key) { gpointer res = NULL; GData *d; GDataElt *data, *data_end; g_return_val_if_fail (datalist != NULL, NULL); g_datalist_lock (datalist); d = G_DATALIST_GET_POINTER (datalist); if (d) { data = d->data; data_end = data + d->len; while (data < data_end) { if ((g_quark_to_string (data->key) != 0) || (key == 0)) /* This line added by JE - 20-10-14 (probably not needed any more) */ if (g_strcmp0 (g_quark_to_string (data->key), key) == 0) { res = data->data; break; } data++; } } g_datalist_unlock (datalist); return res; }
/** * g_datalist_get_data: * @datalist: a datalist. * @key: the string identifying a data element. * * Gets a data element, using its string identifier. This is slower than * g_datalist_id_get_data() because it compares strings. * * Returns: (transfer none) (nullable): the data element, or %NULL if it * is not found. **/ gpointer g_datalist_get_data (GData **datalist, const gchar *key) { gpointer res = NULL; GData *d; GDataElt *data, *data_end; g_return_val_if_fail (datalist != NULL, NULL); g_datalist_lock (datalist); d = G_DATALIST_GET_POINTER (datalist); if (d) { data = d->data; data_end = data + d->len; while (data < data_end) { if (g_strcmp0 (g_quark_to_string (data->key), key) == 0) { res = data->data; break; } data++; } } g_datalist_unlock (datalist); return res; }
/** * g_datalist_id_dup_data: * @datalist: location of a datalist * @key_id: the #GQuark identifying a data element * @dup_func: (allow-none): function to duplicate the old value * @user_data: (allow-none): passed as user_data to @dup_func * * This is a variant of g_datalist_id_get_data() which * returns a 'duplicate' of the value. @dup_func defines the * meaning of 'duplicate' in this context, it could e.g. * take a reference on a ref-counted object. * * If the @key_id is not set in the datalist then @dup_func * will be called with a %NULL argument. * * Note that @dup_func is called while the datalist is locked, so it * is not allowed to read or modify the datalist. * * This function can be useful to avoid races when multiple * threads are using the same datalist and the same key. * * Returns: the result of calling @dup_func on the value * associated with @key_id in @datalist, or %NULL if not set. * If @dup_func is %NULL, the value is returned unmodified. * * Since: 2.34 */ gpointer g_datalist_id_dup_data (GData **datalist, GQuark key_id, GDuplicateFunc dup_func, gpointer user_data) { gpointer val = NULL; gpointer retval = NULL; GData *d; GDataElt *data, *data_end; g_return_val_if_fail (datalist != NULL, NULL); g_return_val_if_fail (key_id != 0, 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; break; } data++; } } if (dup_func) retval = dup_func (val, user_data); else retval = val; g_datalist_unlock (datalist); return retval; }
/** * 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; }