GtkSizeRequestCache: Don't store baselines in horizontal case

This saves memory for every widget (maximum 48 bytes per widget) at
a cost of a few duplicated codepaths in the size request cache.
This commit is contained in:
Alexander Larsson 2013-03-22 12:27:17 +01:00
parent 77e0f18eda
commit 5ad618cb95
2 changed files with 211 additions and 86 deletions

View File

@ -32,31 +32,38 @@ _gtk_size_request_cache_init (SizeRequestCache *cache)
} }
static void static void
free_sizes (SizeRequest **sizes) free_sizes_x (SizeRequestX **sizes)
{ {
gint i; gint i;
for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++) for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
g_slice_free (SizeRequest, sizes[i]); g_slice_free (SizeRequestX, sizes[i]);
g_slice_free1 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes); g_slice_free1 (sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
}
static void
free_sizes_y (SizeRequestY **sizes)
{
gint i;
for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
g_slice_free (SizeRequestY, sizes[i]);
g_slice_free1 (sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
} }
void void
_gtk_size_request_cache_free (SizeRequestCache *cache) _gtk_size_request_cache_free (SizeRequestCache *cache)
{ {
guint i; if (cache->requests_x)
free_sizes_x (cache->requests_x);
for (i = 0; i < 2; i++) if (cache->requests_x)
{ free_sizes_y (cache->requests_y);
if (cache->requests[i])
free_sizes (cache->requests[i]);
}
} }
void void
_gtk_size_request_cache_clear (SizeRequestCache *cache) _gtk_size_request_cache_clear (SizeRequestCache *cache)
{ {
_gtk_size_request_cache_free (cache); _gtk_size_request_cache_free (cache);
_gtk_size_request_cache_init (cache); _gtk_size_request_cache_init (cache);
@ -71,17 +78,30 @@ _gtk_size_request_cache_commit (SizeRequestCache *cache,
gint minimum_baseline, gint minimum_baseline,
gint natural_baseline) gint natural_baseline)
{ {
SizeRequest **cached_sizes;
SizeRequest *cached_size;
guint i, n_sizes; guint i, n_sizes;
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
g_assert (minimum_baseline == -1);
g_assert (natural_baseline == -1);
}
/* First handle caching of the base requests */ /* First handle caching of the base requests */
if (for_size < 0) if (for_size < 0)
{ {
cache->cached_size[orientation].minimum_size = minimum_size; if (orientation == GTK_ORIENTATION_HORIZONTAL)
cache->cached_size[orientation].natural_size = natural_size; {
cache->cached_size[orientation].minimum_baseline = minimum_baseline; cache->cached_size_x.minimum_size = minimum_size;
cache->cached_size[orientation].natural_baseline = natural_baseline; cache->cached_size_x.natural_size = natural_size;
}
else
{
cache->cached_size_y.minimum_size = minimum_size;
cache->cached_size_y.natural_size = natural_size;
cache->cached_size_y.minimum_baseline = minimum_baseline;
cache->cached_size_y.natural_baseline = natural_baseline;
}
cache->flags[orientation].cached_size_valid = TRUE; cache->flags[orientation].cached_size_valid = TRUE;
return; return;
} }
@ -90,49 +110,99 @@ _gtk_size_request_cache_commit (SizeRequestCache *cache,
* in the cache and if this result can be used to extend * in the cache and if this result can be used to extend
* that cache entry * that cache entry
*/ */
cached_sizes = cache->requests[orientation];
n_sizes = cache->flags[orientation].n_cached_requests; n_sizes = cache->flags[orientation].n_cached_requests;
for (i = 0; i < n_sizes; i++)
{
if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
cached_sizes[i]->cached_size.natural_size == natural_size &&
cached_sizes[i]->cached_size.minimum_baseline == minimum_baseline &&
cached_sizes[i]->cached_size.natural_baseline == natural_baseline)
{
cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
return;
}
}
/* If not found, pull a new size from the cache, the returned size cache if (orientation == GTK_ORIENTATION_HORIZONTAL)
* will immediately be used to cache the new computed size so we go ahead
* and increment the last_cached_request right away */
if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
{ {
cache->flags[orientation].n_cached_requests++; SizeRequestX **cached_sizes;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1; SizeRequestX *cached_size;
cached_sizes = cache->requests_x;
for (i = 0; i < n_sizes; i++)
{
if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
cached_sizes[i]->cached_size.natural_size == natural_size)
{
cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
return;
}
}
/* If not found, pull a new size from the cache, the returned size cache
* will immediately be used to cache the new computed size so we go ahead
* and increment the last_cached_request right away */
if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
{
cache->flags[orientation].n_cached_requests++;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
}
else
{
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->flags[orientation].last_cached_request = 0;
}
if (cache->requests_x == NULL)
cache->requests_x = g_slice_alloc0 (sizeof (SizeRequestX *) * GTK_SIZE_REQUEST_CACHED_SIZES);
if (cache->requests_x[cache->flags[orientation].last_cached_request] == NULL)
cache->requests_x[cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequestX);
cached_size = cache->requests_x[cache->flags[orientation].last_cached_request];
cached_size->lower_for_size = for_size;
cached_size->upper_for_size = for_size;
cached_size->cached_size.minimum_size = minimum_size;
cached_size->cached_size.natural_size = natural_size;
} }
else else
{ {
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES) SizeRequestY **cached_sizes;
cache->flags[orientation].last_cached_request = 0; SizeRequestY *cached_size;
cached_sizes = cache->requests_y;
for (i = 0; i < n_sizes; i++)
{
if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
cached_sizes[i]->cached_size.natural_size == natural_size &&
cached_sizes[i]->cached_size.minimum_baseline == minimum_baseline &&
cached_sizes[i]->cached_size.natural_baseline == natural_baseline)
{
cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
return;
}
}
/* If not found, pull a new size from the cache, the returned size cache
* will immediately be used to cache the new computed size so we go ahead
* and increment the last_cached_request right away */
if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
{
cache->flags[orientation].n_cached_requests++;
cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
}
else
{
if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
cache->flags[orientation].last_cached_request = 0;
}
if (cache->requests_y == NULL)
cache->requests_y = g_slice_alloc0 (sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES);
if (cache->requests_y[cache->flags[orientation].last_cached_request] == NULL)
cache->requests_y[cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequestY);
cached_size = cache->requests_y[cache->flags[orientation].last_cached_request];
cached_size->lower_for_size = for_size;
cached_size->upper_for_size = for_size;
cached_size->cached_size.minimum_size = minimum_size;
cached_size->cached_size.natural_size = natural_size;
cached_size->cached_size.minimum_baseline = minimum_baseline;
cached_size->cached_size.natural_baseline = natural_baseline;
} }
if (cache->requests[orientation] == NULL)
cache->requests[orientation] = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
if (cache->requests[orientation][cache->flags[orientation].last_cached_request] == NULL)
cache->requests[orientation][cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequest);
cached_size = cache->requests[orientation][cache->flags[orientation].last_cached_request];
cached_size->lower_for_size = for_size;
cached_size->upper_for_size = for_size;
cached_size->cached_size.minimum_size = minimum_size;
cached_size->cached_size.natural_size = natural_size;
cached_size->cached_size.minimum_baseline = minimum_baseline;
cached_size->cached_size.natural_baseline = natural_baseline;
} }
/* looks for a cached size request for this for_size. /* looks for a cached size request for this for_size.
@ -149,40 +219,81 @@ _gtk_size_request_cache_lookup (SizeRequestCache *cache,
gint *minimum_baseline, gint *minimum_baseline,
gint *natural_baseline) gint *natural_baseline)
{ {
CachedSize *result = NULL; if (orientation == GTK_ORIENTATION_HORIZONTAL)
if (for_size < 0)
{ {
if (cache->flags[orientation].cached_size_valid) CachedSizeX *result = NULL;
result = &cache->cached_size[orientation];
if (for_size < 0)
{
if (cache->flags[orientation].cached_size_valid)
result = &cache->cached_size_x;
}
else
{
guint i;
/* Search for an already cached size */
for (i = 0; i < cache->flags[orientation].n_cached_requests; i++)
{
SizeRequestX *cur = cache->requests_x[i];
if (cur->lower_for_size <= for_size &&
cur->upper_for_size >= for_size)
{
result = &cur->cached_size;
break;
}
}
}
if (result)
{
*minimum = result->minimum_size;
*natural = result->natural_size;
*minimum_baseline = -1;
*natural_baseline = -1;
return TRUE;
}
else
return FALSE;
} }
else else
{ {
guint i; CachedSizeY *result = NULL;
/* Search for an already cached size */ if (for_size < 0)
for (i = 0; i < cache->flags[orientation].n_cached_requests; i++) {
{ if (cache->flags[orientation].cached_size_valid)
SizeRequest *cur = cache->requests[orientation][i]; result = &cache->cached_size_y;
}
else
{
guint i;
if (cur->lower_for_size <= for_size && /* Search for an already cached size */
cur->upper_for_size >= for_size) for (i = 0; i < cache->flags[orientation].n_cached_requests; i++)
{ {
result = &cur->cached_size; SizeRequestY *cur = cache->requests_y[i];
break;
} if (cur->lower_for_size <= for_size &&
} cur->upper_for_size >= for_size)
{
result = &cur->cached_size;
break;
}
}
}
if (result)
{
*minimum = result->minimum_size;
*natural = result->natural_size;
*minimum_baseline = result->minimum_baseline;
*natural_baseline = result->natural_baseline;
return TRUE;
}
else
return FALSE;
} }
if (result)
{
*minimum = result->minimum_size;
*natural = result->natural_size;
*minimum_baseline = result->minimum_baseline;
*natural_baseline = result->natural_baseline;
return TRUE;
}
else
return FALSE;
} }

View File

@ -38,24 +38,38 @@ G_BEGIN_DECLS
*/ */
#define GTK_SIZE_REQUEST_CACHED_SIZES (5) #define GTK_SIZE_REQUEST_CACHED_SIZES (5)
typedef struct {
gint minimum_size;
gint natural_size;
} CachedSizeX;
typedef struct { typedef struct {
gint minimum_size; gint minimum_size;
gint natural_size; gint natural_size;
gint minimum_baseline; gint minimum_baseline;
gint natural_baseline; gint natural_baseline;
} CachedSize; } CachedSizeY;
typedef struct typedef struct
{ {
gint lower_for_size; /* The minimum for_size with the same result */ gint lower_for_size; /* The minimum for_size with the same result */
gint upper_for_size; /* The maximum for_size with the same result */ gint upper_for_size; /* The maximum for_size with the same result */
CachedSize cached_size; CachedSizeX cached_size;
} SizeRequest; } SizeRequestX;
typedef struct
{
gint lower_for_size; /* The minimum for_size with the same result */
gint upper_for_size; /* The maximum for_size with the same result */
CachedSizeY cached_size;
} SizeRequestY;
typedef struct { typedef struct {
SizeRequest **requests[2]; SizeRequestX **requests_x;
SizeRequestY **requests_y;
CachedSize cached_size[2]; CachedSizeX cached_size_x;
CachedSizeY cached_size_y;
GtkSizeRequestMode request_mode : 3; GtkSizeRequestMode request_mode : 3;
guint request_mode_valid : 1; guint request_mode_valid : 1;