[glib/fix-gnulib-msvc-isnan: 20/37] GValue: Add interned string support



commit 9e8862fcf7064773d58eb078cdabff86c90f8b21
Author: Edward Hervey <edward centricular com>
Date:   Fri May 15 07:38:30 2020 +0200

    GValue: Add interned string support
    
    This adds support to be able to explicitely stored interned strings into
    G_TYPE_STRING GValue.
    
    This is useful for cases where the user:
    * *knows* the string to be stored in the GValue is canonical
    * Wants to know whther the string stored is canonical
    
    This allows:
    * zero-cost GValue copy (the content is guaranteed to be unique and exist
      throughout the process life)
    * zero-cost string equality checks (if both string GValue are interned, you just
      need to check the pointers for equality or not, instead of doing a strcmp).
    
    Fixes #2109

 docs/reference/gobject/gobject-sections.txt |  3 ++
 gobject/gvalue.h                            | 10 +++++++
 gobject/gvaluetypes.c                       | 26 +++++++++++++++++
 gobject/gvaluetypes.h                       | 16 +++++++++++
 gobject/tests/value.c                       | 44 +++++++++++++++++++++++++++++
 5 files changed, 99 insertions(+)
---
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index f8b4c89e7..e5ffe5b23 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -684,6 +684,8 @@ G_IS_PARAM_SPEC_STRING
 G_PARAM_SPEC_STRING
 G_VALUE_HOLDS_STRING
 G_TYPE_PARAM_STRING
+G_VALUE_IS_INTERNED_STRING
+G_VALUE_INTERNED_STRING
 GParamSpecString
 gchararray
 g_param_spec_string
@@ -693,6 +695,7 @@ g_value_take_string
 g_value_set_string_take_ownership
 g_value_get_string
 g_value_dup_string
+g_value_set_interned_string
 
 <SUBSECTION GParamSpec>
 G_IS_PARAM_SPEC_PARAM
diff --git a/gobject/gvalue.h b/gobject/gvalue.h
index 9d8f03482..1c6d7377c 100644
--- a/gobject/gvalue.h
+++ b/gobject/gvalue.h
@@ -175,6 +175,16 @@ void       g_value_register_transform_func (GType           src_type,
  */
 #define G_VALUE_NOCOPY_CONTENTS (1 << 27)
 
+/**
+ * G_VALUE_INTERNED_STRING:
+ *
+ * For string values, indicates that the string contained is canonical and will
+ * exist for the duration of the process. See g_value_set_interned_string().
+ *
+ * Since: 2.66
+ */
+#define G_VALUE_INTERNED_STRING (1 << 28) GLIB_AVAILABLE_MACRO_IN_2_66
+
 /**
  * G_VALUE_INIT:
  *
diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c
index 755ddeae1..8052c315e 100644
--- a/gobject/gvaluetypes.c
+++ b/gobject/gvaluetypes.c
@@ -1062,6 +1062,9 @@ g_value_set_string (GValue        *value,
  * Set the contents of a %G_TYPE_STRING #GValue to @v_string.
  * The string is assumed to be static, and is thus not duplicated
  * when setting the #GValue.
+ *
+ * If the the string is a canonical string, using g_value_set_interned_string()
+ * is more appropriate.
  */
 void
 g_value_set_static_string (GValue      *value,
@@ -1075,6 +1078,29 @@ g_value_set_static_string (GValue      *value,
   value->data[0].v_pointer = (gchar*) v_string;
 }
 
+/**
+ * g_value_set_interned_string:
+ * @value: a valid #GValue of type %G_TYPE_STRING
+ * @v_string: (nullable): static string to be set
+ *
+ * Set the contents of a %G_TYPE_STRING #GValue to @v_string.  The string is
+ * assumed to be static and interned (canonical, for example from
+ * g_intern_string()), and is thus not duplicated when setting the #GValue.
+ *
+ * Since: 2.66
+ */
+void
+g_value_set_interned_string (GValue *value,
+                             const gchar *v_string)
+{
+  g_return_if_fail (G_VALUE_HOLDS_STRING (value));
+
+  if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
+    g_free (value->data[0].v_pointer);
+  value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS | G_VALUE_INTERNED_STRING;
+  value->data[0].v_pointer = (gchar *) v_string;
+}
+
 /**
  * g_value_set_string_take_ownership:
  * @value: a valid #GValue of type %G_TYPE_STRING
diff --git a/gobject/gvaluetypes.h b/gobject/gvaluetypes.h
index 927443532..df2f0aa99 100644
--- a/gobject/gvaluetypes.h
+++ b/gobject/gvaluetypes.h
@@ -136,6 +136,19 @@ G_BEGIN_DECLS
  * Returns: %TRUE on success.
  */
 #define G_VALUE_HOLDS_STRING(value)     (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_STRING))
+/**
+ * G_VALUE_IS_INTERNED_STRING:
+ * @value: a valid #GValue structure
+ *
+ * Checks whether @value contains a string which is canonical.
+ *
+ * Returns: %TRUE if the value contains a string in its canonical
+ * representation, as returned by g_intern_string(). See also
+ * g_value_set_interned_string().
+ *
+ * Since: 2.66
+ */
+#define G_VALUE_IS_INTERNED_STRING(value) (G_VALUE_HOLDS_STRING (value) && ((value)->data[1].v_uint & 
G_VALUE_INTERNED_STRING)) GLIB_AVAILABLE_MACRO_IN_2_66
 /**
  * G_VALUE_HOLDS_POINTER:
  * @value: a valid #GValue structure
@@ -241,6 +254,9 @@ void                      g_value_set_string        (GValue       *value,
 GLIB_AVAILABLE_IN_ALL
 void                 g_value_set_static_string (GValue       *value,
                                                 const gchar  *v_string);
+GLIB_AVAILABLE_IN_2_66
+void                 g_value_set_interned_string (GValue      *value,
+                                                  const gchar  *v_string);
 GLIB_AVAILABLE_IN_ALL
 const gchar *         g_value_get_string       (const GValue *value);
 GLIB_AVAILABLE_IN_ALL
diff --git a/gobject/tests/value.c b/gobject/tests/value.c
index 1b2446c88..af918dde9 100644
--- a/gobject/tests/value.c
+++ b/gobject/tests/value.c
@@ -163,6 +163,50 @@ test_value_string (void)
   g_assert_cmpstr (storedstr, ==, static2);
 
   g_value_unset (&value);
+
+  /*
+   * Interned/Canonical strings
+   */
+  static1 = g_intern_static_string (static1);
+  g_value_init (&value, G_TYPE_STRING);
+  g_assert_true (G_VALUE_HOLDS_STRING (&value));
+  g_value_set_interned_string (&value, static1);
+  g_assert_true (G_VALUE_IS_INTERNED_STRING (&value));
+  /* The contents should be the string we provided */
+  storedstr = g_value_get_string (&value);
+  g_assert_true (storedstr == static1);
+  /* But g_value_dup_string() should provide a copy */
+  str2 = g_value_dup_string (&value);
+  g_assert_true (storedstr != str2);
+  g_assert_cmpstr (str2, ==, static1);
+  g_free (str2);
+
+  /* Copying an interned string gvalue should *not* copy the contents
+   * and should still be an interned string */
+  g_value_init (&copy, G_TYPE_STRING);
+  g_value_copy (&value, &copy);
+  g_assert_true (G_VALUE_IS_INTERNED_STRING (&copy));
+  copystr = g_value_get_string (&copy);
+  g_assert_true (copystr == static1);
+  g_value_unset (&copy);
+
+  /* Setting a new interned string should change the contents */
+  static2 = g_intern_static_string (static2);
+  g_value_set_interned_string (&value, static2);
+  g_assert_true (G_VALUE_IS_INTERNED_STRING (&value));
+  /* The contents should be the interned string */
+  storedstr = g_value_get_string (&value);
+  g_assert_cmpstr (storedstr, ==, static2);
+
+  /* Setting a new regular string should change the contents */
+  g_value_set_string (&value, static2);
+  g_assert_false (G_VALUE_IS_INTERNED_STRING (&value));
+  /* The contents should be a copy of that *new* string */
+  storedstr = g_value_get_string (&value);
+  g_assert_true (storedstr != static2);
+  g_assert_cmpstr (storedstr, ==, static2);
+
+  g_value_unset (&value);
 }
 
 static gint


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