mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 06:32:10 +01:00
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
This commit is contained in:
parent
c964749de6
commit
1a95ce84ed
@ -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
|
||||
|
@ -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:
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 (©, G_TYPE_STRING);
|
||||
g_value_copy (&value, ©);
|
||||
g_assert_true (G_VALUE_IS_INTERNED_STRING (©));
|
||||
copystr = g_value_get_string (©);
|
||||
g_assert_true (copystr == static1);
|
||||
g_value_unset (©);
|
||||
|
||||
/* 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user