[glib] gobject: Add to_string() functions for Enum and Flags types



commit 6c95cd22e99380a62090fd3d6c010c40563137e5
Author: Garrett Regier <garrettregier gmail com>
Date:   Thu May 14 03:09:30 2015 -0700

    gobject: Add to_string() functions for Enum and Flags types
    
    These are useful for debugging.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=447907

 docs/reference/gobject/gobject-sections.txt |    2 +
 gobject/genums.c                            |  127 +++++++++++++++++++++++++++
 gobject/genums.h                            |    6 ++
 gobject/gvaluetransform.c                   |   18 ++--
 gobject/tests/enums.c                       |   44 +++++++++-
 5 files changed, 186 insertions(+), 11 deletions(-)
---
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index 0f14f93..be95c1c 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -351,9 +351,11 @@ GFlagsValue
 g_enum_get_value
 g_enum_get_value_by_name
 g_enum_get_value_by_nick
+g_enum_to_string
 g_flags_get_first_value
 g_flags_get_value_by_name
 g_flags_get_value_by_nick
+g_flags_to_string
 g_enum_register_static
 g_flags_register_static
 g_enum_complete_type_info
diff --git a/gobject/genums.c b/gobject/genums.c
index a4f22c9..469f798 100644
--- a/gobject/genums.c
+++ b/gobject/genums.c
@@ -567,6 +567,133 @@ g_flags_get_first_value (GFlagsClass *flags_class,
 }
 
 /**
+ * g_enum_to_string:
+ * @g_enum_type: the type identifier of a #GEnumClass type
+ * @value: the value
+ *
+ * Pretty-prints @value in the form of the enum’s name.
+ *
+ * This is intended to be used for debugging purposes. The format of the output
+ * may change in the future.
+ *
+ * Returns: (transfer full): a newly-allocated text string
+ *
+ * Since: 2.54
+ */
+gchar *
+g_enum_to_string (GType g_enum_type,
+                  gint  value)
+{
+  gchar *result;
+  GEnumClass *enum_class;
+  GEnumValue *enum_value;
+
+  g_return_val_if_fail (G_TYPE_IS_ENUM (g_enum_type), NULL);
+
+  enum_class = g_type_class_ref (g_enum_type);
+
+  /* Already warned */
+  if (enum_class == NULL)
+    return g_strdup_printf ("%d", value);
+
+  enum_value = g_enum_get_value (enum_class, value);
+
+  if (enum_value == NULL)
+    result = g_strdup_printf ("%d", value);
+  else
+    result = g_strdup (enum_value->value_name);
+
+  g_type_class_unref (enum_class);
+  return result;
+}
+
+/*
+ * g_flags_get_value_string:
+ * @flags_class: a #GFlagsClass
+ * @value: the value
+ *
+ * Pretty-prints @value in the form of the flag names separated by ` | ` and
+ * sorted. Any extra bits will be shown at the end as a hexadecimal number.
+ *
+ * This is intended to be used for debugging purposes. The format of the output
+ * may change in the future.
+ *
+ * Returns: (transfer full): a newly-allocated text string
+ *
+ * Since: 2.54
+ */
+static gchar *
+g_flags_get_value_string (GFlagsClass *flags_class,
+                          guint        value)
+{
+  GString *str;
+  GFlagsValue *flags_value;
+
+  g_return_val_if_fail (G_IS_FLAGS_CLASS (flags_class), NULL);
+
+  str = g_string_new (NULL);
+
+  while ((str->len == 0 || value != 0) &&
+         (flags_value = g_flags_get_first_value (flags_class, value)) != NULL)
+    {
+      if (str->len > 0)
+        g_string_append (str, " | ");
+
+      g_string_append (str, flags_value->value_name);
+
+      value &= ~flags_value->value;
+    }
+
+  /* Show the extra bits */
+  if (value != 0 || str->len == 0)
+    {
+      if (str->len > 0)
+        g_string_append (str, " | ");
+
+      g_string_append_printf (str, "0x%x", value);
+    }
+
+  return g_string_free (str, FALSE);
+}
+
+/**
+ * g_flags_to_string:
+ * @flags_type: the type identifier of a #GFlagsClass type
+ * @value: the value
+ *
+ * Pretty-prints @value in the form of the flag names separated by ` | ` and
+ * sorted. Any extra bits will be shown at the end as a hexadecimal number.
+ *
+ * This is intended to be used for debugging purposes. The format of the output
+ * may change in the future.
+ *
+ * Returns: (transfer full): a newly-allocated text string
+ *
+ * Since: 2.54
+ */
+gchar *
+g_flags_to_string (GType flags_type,
+                   guint value)
+{
+  gchar *result;
+  GFlagsClass *flags_class;
+
+  g_return_val_if_fail (G_TYPE_IS_FLAGS (flags_type), NULL);
+
+  flags_class = g_type_class_ref (flags_type);
+
+  /* Already warned */
+  if (flags_class == NULL)
+    return NULL;
+
+  result = g_flags_get_value_string (flags_class, value);
+
+  g_type_class_unref (flags_class);
+  return result;
+}
+
+
+/**
  * g_value_set_enum:
  * @value: a valid #GValue whose type is derived from %G_TYPE_ENUM
  * @v_enum: enum value to be set
diff --git a/gobject/genums.h b/gobject/genums.h
index 15c9d81..109d798 100644
--- a/gobject/genums.h
+++ b/gobject/genums.h
@@ -233,6 +233,12 @@ GFlagsValue*       g_flags_get_value_by_name       (GFlagsClass    *flags_class,
 GLIB_AVAILABLE_IN_ALL
 GFlagsValue*   g_flags_get_value_by_nick       (GFlagsClass    *flags_class,
                                                 const gchar    *nick);
+GLIB_AVAILABLE_IN_2_54
+gchar          *g_enum_to_string                (GType           g_enum_type,
+                                                 gint            value);
+GLIB_AVAILABLE_IN_2_54
+gchar          *g_flags_to_string               (GType           flags_type,
+                                                 guint           value);
 GLIB_AVAILABLE_IN_ALL
 void            g_value_set_enum               (GValue         *value,
                                                 gint            v_enum);
diff --git a/gobject/gvaluetransform.c b/gobject/gvaluetransform.c
index 5579e7f..48051f8 100644
--- a/gobject/gvaluetransform.c
+++ b/gobject/gvaluetransform.c
@@ -183,15 +183,10 @@ static void
 value_transform_enum_string (const GValue *src_value,
                              GValue       *dest_value)
 {
-  GEnumClass *class = g_type_class_ref (G_VALUE_TYPE (src_value));
-  GEnumValue *enum_value = g_enum_get_value (class, src_value->data[0].v_long);
-  
-  if (enum_value)
-    dest_value->data[0].v_pointer = g_strdup (enum_value->value_name);
-  else
-    dest_value->data[0].v_pointer = g_strdup_printf ("%ld", src_value->data[0].v_long);
-  
-  g_type_class_unref (class);
+  gint v_enum = src_value->data[0].v_long;
+  gchar *str = g_enum_to_string (G_VALUE_TYPE (src_value), v_enum);
+
+  dest_value->data[0].v_pointer = str;
 }
 static void
 value_transform_flags_string (const GValue *src_value,
@@ -199,7 +194,10 @@ value_transform_flags_string (const GValue *src_value,
 {
   GFlagsClass *class = g_type_class_ref (G_VALUE_TYPE (src_value));
   GFlagsValue *flags_value = g_flags_get_first_value (class, src_value->data[0].v_ulong);
-  
+
+  /* Note: this does not use g_flags_to_string()
+   * to keep backwards compatibility.
+   */
   if (flags_value)
     {
       GString *gstring = g_string_new (NULL);
diff --git a/gobject/tests/enums.c b/gobject/tests/enums.c
index 84ffed7..3b96417 100644
--- a/gobject/tests/enums.c
+++ b/gobject/tests/enums.c
@@ -15,6 +15,7 @@ test_enum_basic (void)
   GEnumClass *class;
   GEnumValue *val;
   GValue value = G_VALUE_INIT;
+  gchar *to_string;
 
   type = g_enum_register_static ("MyEnum", my_enum_values);
 
@@ -49,6 +50,14 @@ test_enum_basic (void)
   val = g_enum_get_value_by_nick (class, "purple");
   g_assert (val == NULL);
 
+  to_string = g_enum_to_string (type, 2);
+  g_assert_cmpstr (to_string, ==, "the second value");
+  g_free (to_string);
+
+  to_string = g_enum_to_string (type, 15);
+  g_assert_cmpstr (to_string, ==, "15");
+  g_free (to_string);
+
   g_type_class_unref (class);
 }
 
@@ -61,6 +70,12 @@ static const GFlagsValue my_flag_values[] =
   { 0, NULL, NULL }
 };
 
+static const GFlagsValue no_default_flag_values[] =
+{
+  { 1, "the first flag", "one" },
+  { 0, NULL, NULL }
+};
+
 static void
 test_flags_transform_to_string (const GValue *value)
 {
@@ -74,12 +89,15 @@ test_flags_transform_to_string (const GValue *value)
 static void
 test_flags_basic (void)
 {
-  GType type;
+  GType type, no_default_type;
   GFlagsClass *class;
   GFlagsValue *val;
   GValue value = G_VALUE_INIT;
+  gchar *to_string;
 
   type = g_flags_register_static ("MyFlags", my_flag_values);
+  no_default_type = g_flags_register_static ("NoDefaultFlags",
+                                             no_default_flag_values);
 
   g_value_init (&value, type);
   g_assert (G_VALUE_HOLDS_FLAGS (&value));
@@ -113,6 +131,30 @@ test_flags_basic (void)
   test_flags_transform_to_string (&value);
   g_value_unset (&value);
 
+  to_string = g_flags_to_string (type, 1|8);
+  g_assert_cmpstr (to_string, ==, "the first flag | the third flag");
+  g_free (to_string);
+
+  to_string = g_flags_to_string (type, 0);
+  g_assert_cmpstr (to_string, ==, "no flags");
+  g_free (to_string);
+
+  to_string = g_flags_to_string (type, 16);
+  g_assert_cmpstr (to_string, ==, "0x10");
+  g_free (to_string);
+
+  to_string = g_flags_to_string (type, 1|16);
+  g_assert_cmpstr (to_string, ==, "the first flag | 0x10");
+  g_free (to_string);
+
+  to_string = g_flags_to_string (no_default_type, 0);
+  g_assert_cmpstr (to_string, ==, "0x0");
+  g_free (to_string);
+
+  to_string = g_flags_to_string (no_default_type, 16);
+  g_assert_cmpstr (to_string, ==, "0x10");
+  g_free (to_string);
+
   g_type_class_unref (class);
 }
 


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