gdatalist: rework g_data_remove_internal() to use datalist_shrink()

The main point here is to reuse datalist_remove() and datalist_shrink().
Especially, datalist_shrink() will become more interesting next, when it
actually shrinks the buffer.

Also, I find the previous implementation with "data_end" confusing.
Instead, only use index "i_data" to iterate over the data.
This commit is contained in:
Thomas Haller 2024-02-02 17:45:31 +01:00
parent 927075277c
commit 6c0d4c884f

View File

@ -200,6 +200,11 @@ datalist_remove (GData *data, guint32 idx)
g_assert (idx < data->len); g_assert (idx < data->len);
#endif #endif
/* g_data_remove_internal() relies on the fact, that this function removes
* the entry similar to g_array_remove_index_fast(). That is, the entries up
* to @idx are left unchanged, and the last entry at moved to position @idx.
* */
data->len--; data->len--;
if (idx != data->len) if (idx != data->len)
@ -481,10 +486,10 @@ g_data_remove_internal (GData **datalist,
GData *d; GData *d;
GDataElt *old; GDataElt *old;
GDataElt *old_to_free = NULL; GDataElt *old_to_free = NULL;
GDataElt *data; GData *d_to_free;
GDataElt *data_end;
gsize found_keys; gsize found_keys;
gboolean free_d = FALSE; gsize i_keys;
guint32 i_data;
d = g_datalist_lock_and_get (datalist); d = g_datalist_lock_and_get (datalist);
@ -510,68 +515,50 @@ g_data_remove_internal (GData **datalist,
old = old_to_free; old = old_to_free;
} }
data = d->data; i_data = 0;
data_end = data + d->len;
found_keys = 0; found_keys = 0;
while (i_data < d->len && found_keys < n_keys)
while (data < data_end && found_keys < n_keys)
{ {
GDataElt *data = &d->data[i_data];
gboolean remove = FALSE; gboolean remove = FALSE;
for (gsize i = 0; i < n_keys; i++) for (i_keys = 0; i_keys < n_keys; i_keys++)
{ {
if (data->key == keys[i]) if (data->key == keys[i_keys])
{ {
old[i] = *data; /* We must invoke the destroy notifications in the order of @keys.
* Hence, build up the list @old at index @i_keys. */
old[i_keys] = *data;
found_keys++;
remove = TRUE; remove = TRUE;
break; break;
} }
} }
if (remove) if (!remove)
{ {
GDataElt *data_last = data_end - 1; i_data++;
continue;
found_keys++;
if (data < data_last)
*data = *data_last;
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)
{
free_d = TRUE;
break;
}
}
else
{
data++;
} }
datalist_remove (d, i_data);
} }
if (free_d) if (found_keys > 0 && datalist_shrink (&d, &d_to_free))
{ {
g_datalist_unlock_and_set (datalist, NULL); g_datalist_unlock_and_set (datalist, d);
g_free (d); if (d_to_free)
g_free (d_to_free);
} }
else else
g_datalist_unlock (datalist); g_datalist_unlock (datalist);
if (found_keys > 0) if (found_keys > 0)
{ {
for (gsize i = 0; i < n_keys; i++) for (i_keys = 0; i_keys < n_keys; i_keys++)
{ {
/* If keys[i] was not found, then old[i].destroy is NULL. if (old[i_keys].destroy)
* Call old[i].destroy() only if keys[i] was found, and old[i_keys].destroy (old[i_keys].data);
* is associated with a destroy notifier: */
if (old[i].destroy)
old[i].destroy (old[i].data);
} }
} }