mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-28 23:16:14 +01:00
gdataset: add datalist_realloc() helper
This will be more useful next. Also, try to detect whether realloc() actually moved the pointer. If it doesn't, we can optimize a bit (not use g_datalist_unlock_and_set()). Next, we will do more useful optimization in this case. Note that we cannot just compare dangling pointers. That's would be undefined behavior. In practice, we probably often compare dangling pointers, and this tends to work just fine. Still avoid this and compare only the guintptr values.
This commit is contained in:
parent
9a8e2ab263
commit
cc53252c5b
@ -165,6 +165,30 @@ datalist_alloc_size (guint32 alloc)
|
||||
(((gsize) alloc) * sizeof (GDataElt));
|
||||
}
|
||||
|
||||
static GData *
|
||||
datalist_realloc (GData *data, guint32 alloc, gboolean *out_reallocated)
|
||||
{
|
||||
guintptr data_old;
|
||||
gboolean reallocated;
|
||||
|
||||
data_old = (guintptr) ((gpointer) data);
|
||||
|
||||
data = g_realloc (data, datalist_alloc_size (alloc));
|
||||
|
||||
/* Determine whether realloc() moves the pointer. After a move, the old
|
||||
* pointer would be dangling and comparing it would be undefined behavior.
|
||||
* Avoid that by casting to uintptr_t.
|
||||
*/
|
||||
reallocated = (((guintptr) ((gpointer) (data))) != data_old);
|
||||
|
||||
data->alloc = alloc;
|
||||
|
||||
if (out_reallocated)
|
||||
*out_reallocated = reallocated;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
datalist_append (GData **data, GQuark key_id, gpointer new_data, GDestroyNotify destroy_func)
|
||||
{
|
||||
@ -182,7 +206,8 @@ datalist_append (GData **data, GQuark key_id, gpointer new_data, GDestroyNotify
|
||||
}
|
||||
else if (d->len == d->alloc)
|
||||
{
|
||||
d->alloc = d->alloc * 2u;
|
||||
guint32 alloc = d->alloc * 2u;
|
||||
|
||||
#if G_ENABLE_DEBUG
|
||||
/* d->alloc is always a power of two. It thus overflows the first time
|
||||
* when going to (G_MAXUINT32+1), or when requesting 2^31+1 elements.
|
||||
@ -190,11 +215,10 @@ datalist_append (GData **data, GQuark key_id, gpointer new_data, GDestroyNotify
|
||||
* This is not handled, and we just crash. That's because we track the GData
|
||||
* in a linear list, which horribly degrades long before we add 2 billion entries.
|
||||
* Don't ever try to do that. */
|
||||
g_assert (d->alloc > d->len);
|
||||
g_assert (alloc > d->len);
|
||||
#endif
|
||||
d = g_realloc (d, datalist_alloc_size (d->alloc));
|
||||
d = datalist_realloc (d, alloc, &reallocated);
|
||||
*data = d;
|
||||
reallocated = TRUE;
|
||||
}
|
||||
else
|
||||
reallocated = FALSE;
|
||||
@ -230,6 +254,7 @@ datalist_remove (GData *data, guint32 idx)
|
||||
static gboolean
|
||||
datalist_shrink (GData **data, GData **d_to_free)
|
||||
{
|
||||
gboolean reallocated;
|
||||
guint32 alloc_by_4;
|
||||
guint32 v;
|
||||
GData *d;
|
||||
@ -274,11 +299,10 @@ datalist_shrink (GData **data, GData **d_to_free)
|
||||
g_assert (v <= d->alloc / 2u);
|
||||
#endif
|
||||
|
||||
d->alloc = v;
|
||||
d = g_realloc (d, datalist_alloc_size (v));
|
||||
d = datalist_realloc (d, v, &reallocated);
|
||||
*d_to_free = NULL;
|
||||
*data = d;
|
||||
return TRUE;
|
||||
return reallocated;
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user