[gtk/wip/chergert/fix-class-private-data-usage: 1/3] gtk: add bitarray for use by widget muxer



commit 8d1588a0de21e46711b3991a54380121d634881b
Author: Christian Hergert <chergert redhat com>
Date:   Fri Mar 20 09:15:29 2020 -0700

    gtk: add bitarray for use by widget muxer
    
    We need a compact bitarray to track widget enabled state without having
    to allocate a gboolean for each action. Additionally, the common case (of
    up to 64 actions in a single widget) requires no additional allocation
    beyond the embedding of the BitArray.
    
    The bit array dynamically grows based on the position requested. You can
    also set a default value for the bits so that consumers do not need to
    invert the value for cases where TRUE is the default (such as the use by
    GtkActionMuxer).

 gtk/bitarray.c  | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/bitarray.h  |  40 +++++++++++++++
 gtk/meson.build |   1 +
 3 files changed, 191 insertions(+)
---
diff --git a/gtk/bitarray.c b/gtk/bitarray.c
new file mode 100644
index 0000000000..05a0bde88c
--- /dev/null
+++ b/gtk/bitarray.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bitarray.h"
+
+#define BIT_ARRAY_MASK(onoff) (onoff ? (gpointer)(~(guintptr)0) : NULL)
+
+static void
+bit_array_expand_from_static (BitArray *ba,
+                              guint     n_bytes)
+{
+  guint8 *old = ba->data;
+  gpointer default_value;
+
+  ba->data = g_malloc (n_bytes);
+  memcpy (ba->data, &old, GLIB_SIZEOF_VOID_P);
+
+  default_value = BIT_ARRAY_MASK (ba->default_value);
+  for (guint i = ba->n_bytes; i < n_bytes; i++)
+    ba->data[i] = GPOINTER_TO_UINT (default_value) & 0xFF;
+
+  ba->n_bytes = n_bytes;
+}
+
+static void
+bit_array_expand_realloc (BitArray *ba,
+                          guint     n_bytes)
+{
+  gpointer default_value;
+
+  ba->data = g_realloc (ba->data, n_bytes);
+
+  default_value = BIT_ARRAY_MASK (ba->default_value);
+  for (guint i = ba->n_bytes; i < n_bytes; i++)
+    ba->data[i] = GPOINTER_TO_UINT (default_value) & 0xFF;
+
+  ba->n_bytes = n_bytes;
+}
+
+void
+bit_array_init (BitArray *ba,
+                gboolean  default_value)
+{
+  ba->default_value = !!default_value;
+  ba->n_bytes = GLIB_SIZEOF_VOID_P;
+  ba->data = BIT_ARRAY_MASK (default_value);
+}
+
+void
+bit_array_clear (BitArray *ba)
+{
+  if (ba->n_bytes != GLIB_SIZEOF_VOID_P)
+    g_free (ba->data);
+}
+
+void
+bit_array_set (BitArray *ba,
+               guint     position,
+               gboolean  value)
+{
+  guint8 *buf;
+  guint target = position >> 3;
+
+  if (target >= ba->n_bytes)
+    {
+      if (ba->n_bytes == GLIB_SIZEOF_VOID_P)
+        bit_array_expand_from_static (ba, target + 1);
+      else
+        bit_array_expand_realloc (ba, target + 1);
+    }
+
+  if (ba->n_bytes == GLIB_SIZEOF_VOID_P)
+    buf = (gpointer)&ba->data;
+  else
+    buf = ba->data;
+
+  if (value)
+    buf[target] |= (1U << (position & 0x7));
+  else
+    buf[target] &= ~(1U << (position & 0x7));
+}
+
+gboolean
+bit_array_get (BitArray *ba,
+               guint     position)
+{
+  guint8 *buf;
+  guint target = position >> 3;
+
+  if (target >= ba->n_bytes)
+    return ba->default_value;
+
+  if (ba->n_bytes == GLIB_SIZEOF_VOID_P)
+    buf = (gpointer)&ba->data;
+  else
+    buf = ba->data;
+
+  return (buf[target] >> (position & 0x7)) & 0x1;
+}
+
+#if 0
+gint
+main (gint argc,
+      gchar *argv[])
+{
+  BitArray ba;
+
+  bit_array_init (&ba, FALSE);
+  g_assert_true (ba.data == NULL);
+  for (guint i = 0; i < 100; i++)
+    g_assert_cmpint (bit_array_get (&ba, i), ==, FALSE);
+  g_assert_true (ba.data == NULL);
+  bit_array_clear (&ba);
+
+  bit_array_init (&ba, TRUE);
+  g_assert_true (ba.data == BIT_ARRAY_MASK(TRUE));
+  for (guint i = 0; i < 100; i++)
+    g_assert_cmpint (bit_array_get (&ba, i), ==, TRUE);
+  g_assert_true (ba.data == BIT_ARRAY_MASK(TRUE));
+  bit_array_clear (&ba);
+
+  bit_array_init (&ba, TRUE);
+  g_assert_true (ba.data == BIT_ARRAY_MASK(TRUE));
+  for (guint i = 0; i < 1024; i++)
+    {
+      g_assert_cmpint (bit_array_get (&ba, i), ==, TRUE);
+      bit_array_set (&ba, i, FALSE);
+      g_assert_cmpint (bit_array_get (&ba, i), ==, FALSE);
+    }
+  for (guint i = 0; i < 1024; i++)
+    g_assert_cmpint (bit_array_get (&ba, i), ==, FALSE);
+  for (guint i = 0; i < (1024/8); i++)
+    g_assert_false (ba.data[i]);
+  bit_array_clear (&ba);
+}
+#endif
diff --git a/gtk/bitarray.h b/gtk/bitarray.h
new file mode 100644
index 0000000000..8d18289fd2
--- /dev/null
+++ b/gtk/bitarray.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BITARRAY_H__
+#define __BITARRAY_H__
+
+#include <glib.h>
+
+typedef struct _BitArray
+{
+  /*< private >*/
+  guint32  default_value : 1;
+  guint32  n_bytes : 31;
+  guint8  *data;
+} BitArray;
+
+void     bit_array_init  (BitArray *ba,
+                          gboolean  default_value);
+void     bit_array_clear (BitArray *ba);
+void     bit_array_set   (BitArray *ba,
+                          guint     position,
+                          gboolean  value);
+gboolean bit_array_get   (BitArray *ba,
+                          guint     position);
+
+#endif /* __BITARRAY_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index bf7e08a06c..3f3e517f49 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -14,6 +14,7 @@ gtk_cargs = [
 # List of sources that do not contain public API, and should not be
 # introspected
 gtk_private_sources = files([
+  'bitarray.c',
   'fallback-c89.c',
   'fnmatch.c',
   'tools/gdkpixbufutils.c',


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