summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2012-02-09 04:53:43 +0100
committerBenjamin Otte <otte@redhat.com>2012-03-01 15:10:36 +0100
commit6044dfc35b3afb77612cc8a3603e1a0092dfd72a (patch)
tree0b5f4777f56c146263e5fbf7afa3e2c613b4b63c /gtk
parent27eb83a4101adb608949cebebe59c307627d1e9e (diff)
downloadgtk+-6044dfc35b3afb77612cc8a3603e1a0092dfd72a.tar.gz
bitmask: Don't allocate memory for small bitmasks
Code taken more or less verbatim from CoglBitmask.
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkallocatedbitmask.c83
-rw-r--r--gtk/gtkallocatedbitmaskprivate.h14
-rw-r--r--gtk/gtkbitmaskprivateimpl.h72
3 files changed, 132 insertions, 37 deletions
diff --git a/gtk/gtkallocatedbitmask.c b/gtk/gtkallocatedbitmask.c
index ef2ce9face..dff1189edf 100644
--- a/gtk/gtkallocatedbitmask.c
+++ b/gtk/gtkallocatedbitmask.c
@@ -31,6 +31,15 @@ struct _GtkBitmask {
VALUE_TYPE data[1];
};
+#define ENSURE_ALLOCATED(mask, heap_mask) G_STMT_START { \
+ if (!_gtk_bitmask_is_allocated (mask)) \
+ { \
+ heap_mask.data[0] = _gtk_bitmask_to_bits (mask); \
+ heap_mask.len = heap_mask.data[0] ? 1 : 0; \
+ mask = &heap_mask; \
+ } \
+} G_STMT_END
+
static GtkBitmask *
gtk_allocated_bitmask_resize (GtkBitmask *mask,
gsize size) G_GNUC_WARN_UNUSED_RESULT;
@@ -40,7 +49,7 @@ gtk_allocated_bitmask_resize (GtkBitmask *mask,
{
gsize i;
- mask = g_realloc (mask, sizeof (GtkBitmask) + sizeof(VALUE_TYPE) * (MAX (size, 1) - 1));
+ mask = g_realloc (mask, sizeof (GtkBitmask) + sizeof(VALUE_TYPE) * (size - 1));
for (i = mask->len; i < size; i++)
mask->data[i] = 0;
@@ -50,10 +59,25 @@ gtk_allocated_bitmask_resize (GtkBitmask *mask,
return mask;
}
-GtkBitmask *
-_gtk_allocated_bitmask_new (void)
+static GtkBitmask *
+gtk_allocated_bitmask_new_for_bits (gsize bits)
+{
+ GtkBitmask *mask;
+
+ mask = g_malloc (sizeof (GtkBitmask));
+ mask->len = bits ? 1 : 0;
+ mask->data[0] = bits;
+
+ return mask;
+}
+
+static GtkBitmask *
+gtk_bitmask_ensure_allocated (GtkBitmask *mask)
{
- return g_malloc0 (sizeof (GtkBitmask));
+ if (_gtk_bitmask_is_allocated (mask))
+ return mask;
+ else
+ return gtk_allocated_bitmask_new_for_bits (_gtk_bitmask_to_bits (mask));
}
GtkBitmask *
@@ -63,7 +87,7 @@ _gtk_allocated_bitmask_copy (const GtkBitmask *mask)
g_return_val_if_fail (mask != NULL, NULL);
- copy = _gtk_allocated_bitmask_new ();
+ copy = gtk_allocated_bitmask_new_for_bits (0);
return _gtk_allocated_bitmask_union (copy, mask);
}
@@ -80,11 +104,14 @@ void
_gtk_allocated_bitmask_print (const GtkBitmask *mask,
GString *string)
{
+ GtkBitmask mask_allocated;
int i;
g_return_if_fail (mask != NULL);
g_return_if_fail (string != NULL);
+ ENSURE_ALLOCATED (mask, mask_allocated);
+
for (i = mask->len * VALUE_SIZE_BITS - 1; i >= 0; i--)
{
if (_gtk_allocated_bitmask_get (mask, i))
@@ -103,16 +130,6 @@ _gtk_allocated_bitmask_print (const GtkBitmask *mask,
}
}
-char *
-_gtk_allocated_bitmask_to_string (const GtkBitmask *mask)
-{
- GString *string;
-
- string = g_string_new (NULL);
- _gtk_allocated_bitmask_print (mask, string);
- return g_string_free (string, FALSE);
-}
-
/* NB: Call this function whenever the
* array might have become too large.
* _gtk_allocated_bitmask_is_empty() depends on this.
@@ -130,6 +147,14 @@ gtk_allocated_bitmask_shrink (GtkBitmask *mask)
break;
}
+ if (i == 0 ||
+ (i == 1 && mask->data[0] < VALUE_BIT (GTK_BITMASK_N_DIRECT_BITS)))
+ {
+ GtkBitmask *result = _gtk_bitmask_from_bits (i == 0 ? 0 : mask->data[0]);
+ _gtk_allocated_bitmask_free (mask);
+ return result;
+ }
+
return gtk_allocated_bitmask_resize (mask, i);
}
@@ -137,11 +162,15 @@ GtkBitmask *
_gtk_allocated_bitmask_intersect (GtkBitmask *mask,
const GtkBitmask *other)
{
+ GtkBitmask other_allocated;
guint i;
g_return_val_if_fail (mask != NULL, NULL);
g_return_val_if_fail (other != NULL, NULL);
+ mask = gtk_bitmask_ensure_allocated (mask);
+ ENSURE_ALLOCATED (other, other_allocated);
+
mask = gtk_allocated_bitmask_resize (mask, MIN (mask->len, other->len));
for (i = 0; i < mask->len; i++)
{
@@ -155,11 +184,15 @@ GtkBitmask *
_gtk_allocated_bitmask_union (GtkBitmask *mask,
const GtkBitmask *other)
{
+ GtkBitmask other_allocated;
guint i;
g_return_val_if_fail (mask != NULL, NULL);
g_return_val_if_fail (other != NULL, NULL);
+ mask = gtk_bitmask_ensure_allocated (mask);
+ ENSURE_ALLOCATED (other, other_allocated);
+
mask = gtk_allocated_bitmask_resize (mask, MAX (mask->len, other->len));
for (i = 0; i < other->len; i++)
{
@@ -173,11 +206,15 @@ GtkBitmask *
_gtk_allocated_bitmask_subtract (GtkBitmask *mask,
const GtkBitmask *other)
{
+ GtkBitmask other_allocated;
guint i;
g_return_val_if_fail (mask != NULL, NULL);
g_return_val_if_fail (other != NULL, NULL);
+ mask = gtk_bitmask_ensure_allocated (mask);
+ ENSURE_ALLOCATED (other, other_allocated);
+
for (i = 0; i < other->len; i++)
{
mask->data[i] |= ~other->data[i];
@@ -220,6 +257,7 @@ _gtk_allocated_bitmask_set (GtkBitmask *mask,
g_return_val_if_fail (mask != NULL, NULL);
+ mask = gtk_bitmask_ensure_allocated (mask);
gtk_allocated_bitmask_indexes (index_, &array_index, &bit_index);
if (value)
@@ -251,8 +289,9 @@ _gtk_allocated_bitmask_invert_range (GtkBitmask *mask,
g_return_val_if_fail (mask != NULL, NULL);
g_return_val_if_fail (start < end, NULL);
- /* I CAN HAS SPEEDUP? */
+ mask = gtk_bitmask_ensure_allocated (mask);
+ /* I CAN HAS SPEEDUP? */
for (i = start; i < end; i++)
mask = _gtk_allocated_bitmask_set (mask, i, !_gtk_allocated_bitmask_get (mask, i));
@@ -260,14 +299,6 @@ _gtk_allocated_bitmask_invert_range (GtkBitmask *mask,
}
gboolean
-_gtk_allocated_bitmask_is_empty (const GtkBitmask *mask)
-{
- g_return_val_if_fail (mask != NULL, FALSE);
-
- return mask->len == 0;
-}
-
-gboolean
_gtk_allocated_bitmask_equals (const GtkBitmask *mask,
const GtkBitmask *other)
{
@@ -292,11 +323,15 @@ gboolean
_gtk_allocated_bitmask_intersects (const GtkBitmask *mask,
const GtkBitmask *other)
{
+ GtkBitmask mask_allocated, other_allocated;
int i;
g_return_val_if_fail (mask != NULL, FALSE);
g_return_val_if_fail (other != NULL, FALSE);
+ ENSURE_ALLOCATED (mask, mask_allocated);
+ ENSURE_ALLOCATED (other, other_allocated);
+
for (i = MIN (mask->len, other->len) - 1; i >= 0; i--)
{
if (mask->data[i] & other->data[i])
diff --git a/gtk/gtkallocatedbitmaskprivate.h b/gtk/gtkallocatedbitmaskprivate.h
index 023b70d73c..351f68592a 100644
--- a/gtk/gtkallocatedbitmaskprivate.h
+++ b/gtk/gtkallocatedbitmaskprivate.h
@@ -27,12 +27,21 @@ G_BEGIN_DECLS
typedef struct _GtkBitmask GtkBitmask;
+#define _gtk_bitmask_to_bits(mask) \
+ (GPOINTER_TO_SIZE (mask) >> ((gsize) 1))
+
+#define _gtk_bitmask_from_bits(bits) \
+ GSIZE_TO_POINTER ((((gsize) (bits)) << 1) | 1)
+
+#define _gtk_bitmask_is_allocated(mask) \
+ (!(GPOINTER_TO_SIZE (mask) & 1))
+
+#define GTK_BITMASK_N_DIRECT_BITS (sizeof (gsize) * 8 - 1)
+
-GtkBitmask * _gtk_allocated_bitmask_new (void);
GtkBitmask * _gtk_allocated_bitmask_copy (const GtkBitmask *mask);
void _gtk_allocated_bitmask_free (GtkBitmask *mask);
-char * _gtk_allocated_bitmask_to_string (const GtkBitmask *mask);
void _gtk_allocated_bitmask_print (const GtkBitmask *mask,
GString *string);
@@ -53,7 +62,6 @@ GtkBitmask * _gtk_allocated_bitmask_invert_range (GtkBitmask *mask
guint start,
guint end) G_GNUC_WARN_UNUSED_RESULT;
-gboolean _gtk_allocated_bitmask_is_empty (const GtkBitmask *mask);
gboolean _gtk_allocated_bitmask_equals (const GtkBitmask *mask,
const GtkBitmask *other);
gboolean _gtk_allocated_bitmask_intersects (const GtkBitmask *mask,
diff --git a/gtk/gtkbitmaskprivateimpl.h b/gtk/gtkbitmaskprivateimpl.h
index 365d438e3d..e678a81d44 100644
--- a/gtk/gtkbitmaskprivateimpl.h
+++ b/gtk/gtkbitmaskprivateimpl.h
@@ -23,25 +23,33 @@
static inline GtkBitmask *
_gtk_bitmask_new (void)
{
- return _gtk_allocated_bitmask_new ();
+ return _gtk_bitmask_from_bits (0);
}
static inline GtkBitmask *
_gtk_bitmask_copy (const GtkBitmask *mask)
{
- return _gtk_allocated_bitmask_copy (mask);
+ if (_gtk_bitmask_is_allocated (mask))
+ return _gtk_allocated_bitmask_copy (mask);
+ else
+ return (GtkBitmask *) mask;
}
static inline void
_gtk_bitmask_free (GtkBitmask *mask)
{
- return _gtk_allocated_bitmask_free (mask);
+ if (_gtk_bitmask_is_allocated (mask))
+ return _gtk_allocated_bitmask_free (mask);
}
static inline char *
_gtk_bitmask_to_string (const GtkBitmask *mask)
{
- return _gtk_allocated_bitmask_to_string (mask);
+ GString *string;
+
+ string = g_string_new (NULL);
+ _gtk_allocated_bitmask_print (mask, string);
+ return g_string_free (string, FALSE);
}
static inline void
@@ -62,7 +70,12 @@ static inline GtkBitmask *
_gtk_bitmask_union (GtkBitmask *mask,
const GtkBitmask *other)
{
- return _gtk_allocated_bitmask_union (mask, other);
+ if (_gtk_bitmask_is_allocated (mask) ||
+ _gtk_bitmask_is_allocated (other))
+ return _gtk_allocated_bitmask_union (mask, other);
+ else
+ return _gtk_bitmask_from_bits (_gtk_bitmask_to_bits (mask)
+ | _gtk_bitmask_to_bits (other));
}
static inline GtkBitmask *
@@ -76,7 +89,12 @@ static inline gboolean
_gtk_bitmask_get (const GtkBitmask *mask,
guint index_)
{
- return _gtk_allocated_bitmask_get (mask, index_);
+ if (_gtk_bitmask_is_allocated (mask))
+ return _gtk_allocated_bitmask_get (mask, index_);
+ else
+ return index_ < GTK_BITMASK_N_DIRECT_BITS
+ ? !!(_gtk_bitmask_to_bits (mask) & (((size_t) 1) << index_))
+ : FALSE;
}
static inline GtkBitmask *
@@ -84,7 +102,22 @@ _gtk_bitmask_set (GtkBitmask *mask,
guint index_,
gboolean value)
{
- return _gtk_allocated_bitmask_set (mask, index_, value);
+ if (_gtk_bitmask_is_allocated (mask) ||
+ (index_ >= GTK_BITMASK_N_DIRECT_BITS && value))
+ return _gtk_allocated_bitmask_set (mask, index_, value);
+ else if (index_ < GTK_BITMASK_N_DIRECT_BITS)
+ {
+ gsize bits = _gtk_bitmask_to_bits (mask);
+
+ if (value)
+ bits |= ((size_t) 1) << index_;
+ else
+ bits &= ~(((size_t) 1) << index_);
+
+ return _gtk_bitmask_from_bits (bits);
+ }
+ else
+ return mask;
}
static inline GtkBitmask *
@@ -92,19 +125,34 @@ _gtk_bitmask_invert_range (GtkBitmask *mask,
guint start,
guint end)
{
- return _gtk_allocated_bitmask_invert_range (mask, start, end);
+ if (_gtk_bitmask_is_allocated (mask) ||
+ (end > GTK_BITMASK_N_DIRECT_BITS))
+ return _gtk_allocated_bitmask_invert_range (mask, start, end);
+ else
+ {
+ size_t invert = (((size_t) 1) << end) - (((size_t) 1) << start);
+
+ return _gtk_bitmask_from_bits (_gtk_bitmask_to_bits (mask) ^ invert);
+ }
}
static inline gboolean
_gtk_bitmask_is_empty (const GtkBitmask *mask)
{
- return _gtk_allocated_bitmask_is_empty (mask);
+ return mask == _gtk_bitmask_from_bits (0);
}
static inline gboolean
_gtk_bitmask_equals (const GtkBitmask *mask,
const GtkBitmask *other)
{
+ if (mask == other)
+ return TRUE;
+
+ if (!_gtk_bitmask_is_allocated (mask) ||
+ !_gtk_bitmask_is_allocated (other))
+ return FALSE;
+
return _gtk_allocated_bitmask_equals (mask, other);
}
@@ -112,5 +160,9 @@ static inline gboolean
_gtk_bitmask_intersects (const GtkBitmask *mask,
const GtkBitmask *other)
{
- return _gtk_allocated_bitmask_intersects (mask, other);
+ if (!_gtk_bitmask_is_allocated (mask) ||
+ !_gtk_bitmask_is_allocated (other))
+ return _gtk_allocated_bitmask_intersects (mask, other);
+ else
+ return _gtk_bitmask_to_bits (mask) & _gtk_bitmask_to_bits (other);
}