[gtk+/wip/bitmask: 4/4] bitmask: Don't allocate memory for small bitmasks



commit 94639fdff2118ef2487f36cd3dbc94894dc50cd6
Author: Neil Roberts <neil linux intel com>
Date:   Thu Feb 9 04:53:43 2012 +0100

    bitmask: Don't allocate memory for small bitmasks
    
    Code taken more or less verbatim from CoglBitmask.

 gtk/gtkallocatedbitmask.c        |   83 +++++++++++++++++++++++++++-----------
 gtk/gtkallocatedbitmaskprivate.h |   14 +++++-
 gtk/gtkbitmaskprivateimpl.h      |   72 ++++++++++++++++++++++++++++-----
 3 files changed, 132 insertions(+), 37 deletions(-)
---
diff --git a/gtk/gtkallocatedbitmask.c b/gtk/gtkallocatedbitmask.c
index 5b3962d..e101f88 100644
--- a/gtk/gtkallocatedbitmask.c
+++ b/gtk/gtkallocatedbitmask.c
@@ -32,6 +32,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;
@@ -41,7 +50,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;
@@ -51,10 +60,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 *
@@ -64,7 +88,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);
 }
@@ -81,11 +105,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))
@@ -104,16 +131,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.
@@ -131,6 +148,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);
 }
 
@@ -138,11 +163,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++)
     {
@@ -156,11 +185,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++)
     {
@@ -174,11 +207,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];
@@ -221,6 +258,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)
@@ -252,8 +290,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));
 
@@ -261,14 +300,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)
 {
@@ -293,11 +324,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 023b70d..351f685 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 365d438..e678a81 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);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]