summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2012-02-08 14:27:29 +0100
committerAlexander Larsson <alexl@redhat.com>2012-02-08 14:27:29 +0100
commitf9d9b26d980762baa6a259559792330f9783a748 (patch)
tree4fc5913f0a0400399dd3cdf352e89b6494d23086
parent493b7f2719264bf447c2507df9ce0d0772cf3b11 (diff)
downloadgtk+-f9d9b26d980762baa6a259559792330f9783a748.tar.gz
Store GtkBitmap data inline in the pointer
Bitmaps are often sparse in some way, which we can use by storing such bitmaps inside the actual GtkBitmap pointer, which we detect by looking at the least significant bit (which is never set for normal objects due to alignment rules). There are two basic approaches, you can store the bitmasks smaller than 31/63 bits directly in the pointer, or you can use the pointer as a single bit number, considering that bit set. I did some measurements on this, and it turns out that 63 bits is enought for most bitmaps right now, but not 31bit, which means this is only efficient on 64bit arches. Additionally it doesn't scale well as the number of style classes and regions increase. Using the data to store a single bit number however was almost as good as 63 bits always and sometimes better, and it will continue to scale as we add more classes and regions. With this change we use an additional 116KB ram in Nautilus after startup.
-rw-r--r--gtk/gtkbitmask.c305
-rw-r--r--gtk/gtkwidgetpath.c2
2 files changed, 280 insertions, 27 deletions
diff --git a/gtk/gtkbitmask.c b/gtk/gtkbitmask.c
index a616c7a516..2bd64f1c69 100644
--- a/gtk/gtkbitmask.c
+++ b/gtk/gtkbitmask.c
@@ -33,6 +33,12 @@ struct _GtkBitmask {
VALUE_TYPE data[1];
};
+typedef struct {
+ GtkBitmask bitmask;
+ VALUE_TYPE more_data[3];
+ const GtkBitmask *orig;
+} GtkBitmaskPrealloc;
+
static GtkBitmask *
_gtk_bitmask_allocate (guint size)
{
@@ -73,12 +79,111 @@ _gtk_bitmask_resize (GtkBitmask **mask, guint len)
(*mask)->len = len;
}
+static gboolean
+gtk_bitmask_is_bit (const GtkBitmask *mask)
+{
+ return (((gsize)mask) & 1);
+}
+
+static GtkBitmask *
+gtk_bitmask_for_bit (guint bit)
+{
+ gsize mask;
+
+ mask = bit;
+ mask <<= 1;
+ mask |= 1;
+ return (GtkBitmask *)mask;
+}
+
+static guint
+gtk_bitmask_get_bit (const GtkBitmask *mask)
+{
+ return ((gsize)mask) >> 1;
+}
+
+static gboolean
+gtk_bitmask_is_inline (const GtkBitmask *mask)
+{
+ return mask == NULL || gtk_bitmask_is_bit (mask);
+}
+
+static void
+gtk_bitmask_realize_for_write (GtkBitmask **mask, guint size_hint)
+{
+ GtkBitmask *realized;
+
+ if (*mask == NULL)
+ {
+ realized = _gtk_bitmask_allocate (MAX (size_hint, 1));
+ realized->len = 0;
+ *mask = realized;
+ }
+ else if (gtk_bitmask_is_bit (*mask))
+ {
+ guint bit = gtk_bitmask_get_bit (*mask);
+ guint len = (bit / VALUE_SIZE_BITS) + 1;
+ int i;
+
+ realized = _gtk_bitmask_allocate (MAX (len, size_hint));
+ realized->len = len;
+ for (i = 0; i < len; i++)
+ realized->data[i] = 0;
+
+ _gtk_bitmask_set (&realized, bit, TRUE);
+
+ *mask = realized;
+ }
+}
+
+
+static void
+gtk_bitmask_realize (const GtkBitmask **mask, GtkBitmaskPrealloc *prealloc)
+{
+ prealloc->orig = *mask;
+ if (*mask == NULL)
+ {
+ prealloc->bitmask.len = 0;
+ prealloc->bitmask.alloc = 4;
+ *mask = &prealloc->bitmask;
+ }
+ else if (gtk_bitmask_is_bit (*mask))
+ {
+ GtkBitmask *realized;
+ int i;
+ guint bit = gtk_bitmask_get_bit (*mask);
+ guint len = (bit / VALUE_SIZE_BITS) + 1;
+
+ if (len <= 4)
+ {
+ prealloc->bitmask.alloc = 4;
+ realized = &prealloc->bitmask;
+ }
+ else
+ realized = _gtk_bitmask_allocate (len);
+
+ for (i = 0; i < len; i++)
+ realized->data[i] = 0;
+ realized->len = len;
+ _gtk_bitmask_set (&realized, bit, TRUE);
+
+ *mask = realized;
+ }
+}
+
+static void
+gtk_bitmask_unrealize (const GtkBitmask *mask, GtkBitmaskPrealloc *prealloc)
+{
+ if (mask != prealloc->orig &&
+ mask != &prealloc->bitmask)
+ g_free ((GtkBitmask *)mask);
+}
GtkBitmask *
_gtk_bitmask_new (void)
{
- return _gtk_bitmask_allocate (1);
+ return NULL;
}
GtkBitmask *
@@ -86,7 +191,8 @@ _gtk_bitmask_copy (const GtkBitmask *mask)
{
GtkBitmask *copy;
- g_return_val_if_fail (mask != NULL, NULL);
+ if (gtk_bitmask_is_inline (mask))
+ return (GtkBitmask *)mask;
copy = _gtk_bitmask_new ();
_gtk_bitmask_union (&copy, mask);
@@ -97,18 +203,19 @@ _gtk_bitmask_copy (const GtkBitmask *mask)
void
_gtk_bitmask_free (GtkBitmask *mask)
{
- g_return_if_fail (mask != NULL);
-
- g_free (mask);
+ if (!gtk_bitmask_is_inline (mask))
+ g_free (mask);
}
void
_gtk_bitmask_print (const GtkBitmask *mask,
GString *string)
{
+ GtkBitmaskPrealloc mask_prealloc;
int i;
- g_return_if_fail (mask != NULL);
+ gtk_bitmask_realize (&mask, &mask_prealloc);
+
g_return_if_fail (string != NULL);
for (i = mask->len * VALUE_SIZE_BITS - 1; i >= 0; i--)
@@ -120,6 +227,7 @@ _gtk_bitmask_print (const GtkBitmask *mask,
if (i < 0)
{
g_string_append_c (string, '0');
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
return;
}
@@ -127,6 +235,8 @@ _gtk_bitmask_print (const GtkBitmask *mask,
{
g_string_append_c (string, _gtk_bitmask_get (mask, i) ? '1' : '0');
}
+
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
}
char *
@@ -148,58 +258,129 @@ gtk_bitmask_shrink (GtkBitmask **mask)
{
guint i;
+ if (gtk_bitmask_is_inline (*mask))
+ return;
+
for (i = (*mask)->len; i; i--)
{
if ((*mask)->data[i - 1])
break;
}
- (*mask)->len = i;
+ if (i == 0)
+ {
+ g_free (*mask);
+ *mask = NULL;
+ }
+ else
+ (*mask)->len = i;
}
void
_gtk_bitmask_intersect (GtkBitmask **mask,
const GtkBitmask *other)
{
+ GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_if_fail (mask != NULL);
- g_return_if_fail (other != NULL);
+
+ if (gtk_bitmask_is_inline (*mask) &&
+ gtk_bitmask_is_inline (other))
+ {
+ if (mask == NULL || other == NULL)
+ *mask = NULL;
+ else
+ {
+ /* Different bits, the intersection is empty */
+ if (*mask != other)
+ *mask = NULL;
+ /* If same bit, the value is already right */
+ }
+
+ return;
+ }
+
+ gtk_bitmask_realize (&other, &other_prealloc);
+ gtk_bitmask_realize_for_write (mask, 0);
_gtk_bitmask_resize (mask, MIN ((*mask)->len, other->len));
for (i = 0; i < (*mask)->len; i++)
(*mask)->data[i] &= other->data[i];
gtk_bitmask_shrink (mask);
+
+ gtk_bitmask_unrealize (other, &other_prealloc);
}
void
_gtk_bitmask_union (GtkBitmask **mask,
const GtkBitmask *other)
{
+ GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_if_fail (mask != NULL);
- g_return_if_fail (other != NULL);
+
+ if (gtk_bitmask_is_inline (*mask) &&
+ gtk_bitmask_is_inline (other))
+ {
+ /* Union nothing with something is something */
+ if (*mask == NULL)
+ {
+ *mask = (GtkBitmask *)other;
+ return;
+ }
+
+ /* Union with nothing or same is same */
+ if (other == NULL ||
+ *mask == other)
+ return;
+ }
+
+ gtk_bitmask_realize (&other, &other_prealloc);
+ gtk_bitmask_realize_for_write (mask, other->len);
_gtk_bitmask_resize (mask, MAX ((*mask)->len, other->len));
for (i = 0; i < other->len; i++)
(*mask)->data[i] |= other->data[i];
+
+ gtk_bitmask_unrealize (other, &other_prealloc);
}
void
_gtk_bitmask_subtract (GtkBitmask **mask,
const GtkBitmask *other)
{
+ GtkBitmaskPrealloc other_prealloc;
guint i;
g_return_if_fail (mask != NULL);
- g_return_if_fail (other != NULL);
+
+ if (gtk_bitmask_is_inline (*mask) &&
+ gtk_bitmask_is_inline (other))
+ {
+ /* Subtract from nothing, or subtract nothing => no change */
+ if (*mask == NULL ||
+ other == NULL)
+ return;
+
+ /* Subtract the same bit => nothing */
+ if (*mask == other)
+ *mask = NULL;
+ /* Subtract other bit => no change */
+ return;
+ }
+
+ gtk_bitmask_realize (&other, &other_prealloc);
+ gtk_bitmask_realize_for_write (mask, 0);
for (i = 0; i < other->len; i++)
(*mask)->data[i] &= ~(other->data[i]);
gtk_bitmask_shrink (mask);
+
+ gtk_bitmask_unrealize (other, &other_prealloc);
}
static void
@@ -217,7 +398,17 @@ _gtk_bitmask_get (const GtkBitmask *mask,
{
guint array_index, bit_index;
- g_return_val_if_fail (mask != NULL, FALSE);
+ if (mask == NULL)
+ return FALSE;
+
+ if (gtk_bitmask_is_bit (mask))
+ {
+ guint bit = gtk_bitmask_get_bit (mask);
+ if (bit == index_)
+ return TRUE;
+ else
+ return FALSE;
+ }
gtk_bitmask_indexes (index_, &array_index, &bit_index);
@@ -236,6 +427,23 @@ _gtk_bitmask_set (GtkBitmask **mask,
g_return_if_fail (mask != NULL);
+ if (*mask == NULL)
+ {
+ if (value)
+ *mask = gtk_bitmask_for_bit (index_);
+ return;
+ }
+
+ if (gtk_bitmask_is_bit (*mask) &&
+ gtk_bitmask_get_bit (*mask) == index_)
+ {
+ if (!value)
+ *mask = NULL;
+ return;
+ }
+
+ gtk_bitmask_realize_for_write (mask, 0);
+
gtk_bitmask_indexes (index_, &array_index, &bit_index);
if (value)
@@ -274,19 +482,23 @@ _gtk_bitmask_invert_range (GtkBitmask **mask,
gboolean
_gtk_bitmask_is_empty (const GtkBitmask *mask)
{
- g_return_val_if_fail (mask != NULL, FALSE);
-
- return mask->len == 0;
+ return mask == NULL;
}
gboolean
_gtk_bitmask_equals (const GtkBitmask *mask,
const GtkBitmask *other)
{
+ GtkBitmaskPrealloc mask_prealloc;
+ GtkBitmaskPrealloc other_prealloc;
guint i;
- g_return_val_if_fail (mask != NULL, FALSE);
- g_return_val_if_fail (other != NULL, FALSE);
+ if (gtk_bitmask_is_inline (mask) &&
+ gtk_bitmask_is_inline (other))
+ return mask == other;
+
+ gtk_bitmask_realize (&mask, &mask_prealloc);
+ gtk_bitmask_realize (&other, &other_prealloc);
if (mask->len != other->len)
return FALSE;
@@ -297,6 +509,9 @@ _gtk_bitmask_equals (const GtkBitmask *mask,
return FALSE;
}
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
+ gtk_bitmask_unrealize (other, &other_prealloc);
+
return TRUE;
}
@@ -304,36 +519,58 @@ gboolean
_gtk_bitmask_intersects (const GtkBitmask *mask,
const GtkBitmask *other)
{
+ GtkBitmaskPrealloc mask_prealloc;
+ GtkBitmaskPrealloc other_prealloc;
int i;
+ gboolean res;
- g_return_val_if_fail (mask != NULL, FALSE);
- g_return_val_if_fail (other != NULL, FALSE);
+ if (gtk_bitmask_is_inline (mask) &&
+ gtk_bitmask_is_inline (other))
+ {
+ if (mask == NULL || other == NULL)
+ return FALSE;
+
+ if (mask == other)
+ return TRUE;
+ return FALSE;
+ }
+
+ gtk_bitmask_realize (&mask, &mask_prealloc);
+ gtk_bitmask_realize (&other, &other_prealloc);
+
+ res = FALSE;
for (i = MIN (mask->len, other->len) - 1; i >= 0; i--)
{
if (mask->data[i] & other->data[i])
- return TRUE;
+ {
+ res = TRUE;
+ break;
+ }
}
- return FALSE;
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
+ gtk_bitmask_unrealize (other, &other_prealloc);
+
+ return res;
}
void
_gtk_bitmask_clear (GtkBitmask **mask)
{
- g_return_if_fail (mask != NULL);
-
- (*mask)->len = 0;
+ _gtk_bitmask_free (*mask);
+ *mask = NULL;
}
guint
_gtk_bitmask_get_uint (const GtkBitmask *mask,
guint index_)
{
+ GtkBitmaskPrealloc mask_prealloc;
guint array_index, bit_index;
VALUE_TYPE value1, value2;
- g_return_val_if_fail (mask != NULL, FALSE);
+ gtk_bitmask_realize (&mask, &mask_prealloc);
gtk_bitmask_indexes (index_, &array_index, &bit_index);
@@ -349,6 +586,8 @@ _gtk_bitmask_get_uint (const GtkBitmask *mask,
else
value2 = 0;
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
+
return (guint)(value1 | value2);
}
@@ -363,6 +602,8 @@ _gtk_bitmask_set_uint (GtkBitmask **mask,
g_return_if_fail (mask != NULL);
+ gtk_bitmask_realize_for_write (mask, 0);
+
gtk_bitmask_indexes (index_, &array_index, &bit_index);
value1 = value2 = 0;
@@ -401,10 +642,14 @@ _gtk_bitmask_set_uint (GtkBitmask **mask,
guint
_gtk_bitmask_hash (const GtkBitmask *mask)
{
+ GtkBitmaskPrealloc mask_prealloc;
int i;
VALUE_TYPE value, hash;
- g_return_val_if_fail (mask != NULL, FALSE);
+ if (mask == NULL)
+ return 0;
+
+ gtk_bitmask_realize (&mask, &mask_prealloc);
hash = 0;
@@ -417,6 +662,8 @@ _gtk_bitmask_hash (const GtkBitmask *mask)
if (sizeof (hash) > sizeof (guint))
hash = hash ^ (hash >> 32);
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
+
return hash;
}
@@ -424,9 +671,15 @@ gboolean
_gtk_bitmask_find_next_set (const GtkBitmask *mask,
guint *pos)
{
+ GtkBitmaskPrealloc mask_prealloc;
guint array_index, bit_index;
VALUE_TYPE value;
+ if (mask == NULL)
+ return FALSE;
+
+ gtk_bitmask_realize (&mask, &mask_prealloc);
+
gtk_bitmask_indexes (*pos, &array_index, &bit_index);
while (array_index < mask->len)
@@ -447,5 +700,7 @@ _gtk_bitmask_find_next_set (const GtkBitmask *mask,
bit_index = 0;
}
+ gtk_bitmask_unrealize (mask, &mask_prealloc);
+
return FALSE;
}
diff --git a/gtk/gtkwidgetpath.c b/gtk/gtkwidgetpath.c
index b63d191e69..524793640f 100644
--- a/gtk/gtkwidgetpath.c
+++ b/gtk/gtkwidgetpath.c
@@ -736,7 +736,6 @@ _gtk_widget_path_iter_add_classes (GtkWidgetPath *path,
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
- g_return_if_fail (classes != NULL);
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;
@@ -975,7 +974,6 @@ _gtk_widget_path_iter_add_regions (GtkWidgetPath *path,
g_return_if_fail (path != NULL);
g_return_if_fail (path->elems->len != 0);
- g_return_if_fail (regions != NULL);
if (pos < 0 || pos >= path->elems->len)
pos = path->elems->len - 1;