mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-07 18:06:15 +01:00
GVariant: Add a G_VARIANT_DICT_INIT macro
The macro could be used at initialization time to avoid having an unitialized dict, especially with g_auto variables. The macro tries to be a bit more type-safe by making sure that the asv parameter is actually "GVariant *". https://bugzilla.gnome.org/show_bug.cgi?id=766370
This commit is contained in:
parent
e1c640f819
commit
992ded39bf
@ -3796,11 +3796,36 @@ struct heap_dict
|
||||
#define GVSD(d) ((struct stack_dict *) (d))
|
||||
#define GVHD(d) ((struct heap_dict *) (d))
|
||||
#define GVSD_MAGIC ((gsize) 2579507750u)
|
||||
#define GVSD_MAGIC_PARTIAL ((gsize) 3488698669u)
|
||||
#define GVHD_MAGIC ((gsize) 2450270775u)
|
||||
#define is_valid_dict(d) (d != NULL && \
|
||||
GVSD(d)->magic == GVSD_MAGIC)
|
||||
#define is_valid_heap_dict(d) (GVHD(d)->magic == GVHD_MAGIC)
|
||||
|
||||
/* Just to make sure that by adding a union to GVariantDict, we didn't
|
||||
* accidentally change ABI. */
|
||||
G_STATIC_ASSERT (sizeof (GVariantDict) == sizeof (gsize[16]));
|
||||
|
||||
static gboolean
|
||||
ensure_valid_dict (GVariantDict *dict)
|
||||
{
|
||||
if (is_valid_dict (dict))
|
||||
return TRUE;
|
||||
if (dict->partial_magic == GVSD_MAGIC_PARTIAL)
|
||||
{
|
||||
static GVariantDict cleared_dict;
|
||||
|
||||
/* Make sure that only first two fields were set and the rest is
|
||||
* zeroed to avoid messing up the builder that had parent
|
||||
* address equal to GVSB_MAGIC_PARTIAL. */
|
||||
if (memcmp (cleared_dict.y, dict->y, sizeof cleared_dict.y))
|
||||
return FALSE;
|
||||
|
||||
g_variant_dict_init (dict, dict->asv);
|
||||
}
|
||||
return is_valid_dict (dict);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_variant_dict_new:
|
||||
* @from_asv: (allow-none): the #GVariant with which to initialise the
|
||||
@ -3908,7 +3933,7 @@ g_variant_dict_lookup (GVariantDict *dict,
|
||||
GVariant *value;
|
||||
va_list ap;
|
||||
|
||||
g_return_val_if_fail (is_valid_dict (dict), FALSE);
|
||||
g_return_val_if_fail (ensure_valid_dict (dict), FALSE);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
g_return_val_if_fail (format_string != NULL, FALSE);
|
||||
|
||||
@ -3953,7 +3978,7 @@ g_variant_dict_lookup_value (GVariantDict *dict,
|
||||
{
|
||||
GVariant *result;
|
||||
|
||||
g_return_val_if_fail (is_valid_dict (dict), NULL);
|
||||
g_return_val_if_fail (ensure_valid_dict (dict), NULL);
|
||||
g_return_val_if_fail (key != NULL, NULL);
|
||||
|
||||
result = g_hash_table_lookup (GVSD(dict)->values, key);
|
||||
@ -3979,7 +4004,7 @@ gboolean
|
||||
g_variant_dict_contains (GVariantDict *dict,
|
||||
const gchar *key)
|
||||
{
|
||||
g_return_val_if_fail (is_valid_dict (dict), FALSE);
|
||||
g_return_val_if_fail (ensure_valid_dict (dict), FALSE);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
|
||||
return g_hash_table_contains (GVSD(dict)->values, key);
|
||||
@ -4007,7 +4032,7 @@ g_variant_dict_insert (GVariantDict *dict,
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
g_return_if_fail (is_valid_dict (dict));
|
||||
g_return_if_fail (ensure_valid_dict (dict));
|
||||
g_return_if_fail (key != NULL);
|
||||
g_return_if_fail (format_string != NULL);
|
||||
|
||||
@ -4033,7 +4058,7 @@ g_variant_dict_insert_value (GVariantDict *dict,
|
||||
const gchar *key,
|
||||
GVariant *value)
|
||||
{
|
||||
g_return_if_fail (is_valid_dict (dict));
|
||||
g_return_if_fail (ensure_valid_dict (dict));
|
||||
g_return_if_fail (key != NULL);
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
@ -4055,7 +4080,7 @@ gboolean
|
||||
g_variant_dict_remove (GVariantDict *dict,
|
||||
const gchar *key)
|
||||
{
|
||||
g_return_val_if_fail (is_valid_dict (dict), FALSE);
|
||||
g_return_val_if_fail (ensure_valid_dict (dict), FALSE);
|
||||
g_return_val_if_fail (key != NULL, FALSE);
|
||||
|
||||
return g_hash_table_remove (GVSD(dict)->values, key);
|
||||
@ -4089,7 +4114,7 @@ g_variant_dict_clear (GVariantDict *dict)
|
||||
/* all-zeros case */
|
||||
return;
|
||||
|
||||
g_return_if_fail (is_valid_dict (dict));
|
||||
g_return_if_fail (ensure_valid_dict (dict));
|
||||
|
||||
g_hash_table_unref (GVSD(dict)->values);
|
||||
GVSD(dict)->values = NULL;
|
||||
@ -4120,7 +4145,7 @@ g_variant_dict_end (GVariantDict *dict)
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_return_val_if_fail (is_valid_dict (dict), NULL);
|
||||
g_return_val_if_fail (ensure_valid_dict (dict), NULL);
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
|
||||
|
||||
|
@ -436,9 +436,46 @@ gint g_variant_compare (gconstp
|
||||
typedef struct _GVariantDict GVariantDict;
|
||||
struct _GVariantDict {
|
||||
/*< private >*/
|
||||
gsize x[16];
|
||||
union
|
||||
{
|
||||
struct {
|
||||
GVariant *asv;
|
||||
gsize partial_magic;
|
||||
gsize y[14];
|
||||
};
|
||||
gsize x[16];
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* G_VARIANT_DICT_INIT:
|
||||
* @asv: (nullable): a GVariant*
|
||||
*
|
||||
* A stack-allocated #GVariantDict must be initialized if it is used
|
||||
* together with g_auto() to avoid warnings or crashes if function
|
||||
* returns before g_variant_dict_init() is called on the builder.
|
||||
* This macro can be used as initializer instead of an explicit
|
||||
* zeroing a variable when declaring it and a following
|
||||
* g_variant_dict_init(), but it cannot be assigned to a variable.
|
||||
*
|
||||
* The passed @asv has to live long enough for #GVariantDict to gather
|
||||
* the entries from, as the gathering does not happen in the
|
||||
* G_VARIANT_DICT_INIT() call, but rather in functions that make sure
|
||||
* that #GVariantDict is valid. In context where the initialization
|
||||
* value has to be a constant expression, the only possible value of
|
||||
* @asv is %NULL. It is still possible to call g_variant_dict_init()
|
||||
* safely with a different @asv right after the variable was
|
||||
* initialized with G_VARIANT_DICT_INIT().
|
||||
*
|
||||
* |[
|
||||
* g_autoptr(GVariant) variant = get_asv_variant ();
|
||||
* g_auto(GVariantDict) dict = G_VARIANT_DICT_INIT (variant);
|
||||
* ]|
|
||||
*
|
||||
* Since: 2.50
|
||||
*/
|
||||
#define G_VARIANT_DICT_INIT(asv) { { { asv, 3488698669u, { 0, } } } }
|
||||
|
||||
GLIB_AVAILABLE_IN_2_40
|
||||
GVariantDict * g_variant_dict_new (GVariant *from_asv);
|
||||
|
||||
|
@ -4554,6 +4554,51 @@ test_stack_builder_init (void)
|
||||
g_variant_unref (variant);
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
get_asv (void)
|
||||
{
|
||||
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
||||
|
||||
g_variant_builder_add (&builder, "{s@v}", "foo", g_variant_new_variant (g_variant_new_string ("FOO")));
|
||||
g_variant_builder_add (&builder, "{s@v}", "bar", g_variant_new_variant (g_variant_new_string ("BAR")));
|
||||
|
||||
return g_variant_ref_sink (g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
static void
|
||||
test_stack_dict_init (void)
|
||||
{
|
||||
GVariant *asv = get_asv ();
|
||||
GVariantDict dict = G_VARIANT_DICT_INIT (asv);
|
||||
GVariant *variant;
|
||||
GVariantIter iter;
|
||||
gchar *key;
|
||||
GVariant *value;
|
||||
|
||||
g_variant_dict_insert_value (&dict, "baz", g_variant_new_string ("BAZ"));
|
||||
g_variant_dict_insert_value (&dict, "quux", g_variant_new_string ("QUUX"));
|
||||
|
||||
variant = g_variant_ref_sink (g_variant_dict_end (&dict));
|
||||
g_assert_nonnull (variant);
|
||||
g_assert (g_variant_type_equal (g_variant_get_type (variant),
|
||||
G_VARIANT_TYPE_VARDICT));
|
||||
g_assert_cmpuint (g_variant_n_children (variant), ==, 4);
|
||||
|
||||
g_variant_iter_init (&iter, variant);
|
||||
while (g_variant_iter_next (&iter, "{sv}", &key, &value))
|
||||
{
|
||||
gchar *strup = g_ascii_strup (key, -1);
|
||||
|
||||
g_assert_cmpstr (strup, ==, g_variant_get_string (value, NULL));
|
||||
g_free (key);
|
||||
g_free (strup);
|
||||
g_variant_unref (value);
|
||||
}
|
||||
|
||||
g_variant_unref (asv);
|
||||
g_variant_unref (variant);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -4614,5 +4659,6 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/gvariant/error-quark", test_error_quark);
|
||||
|
||||
g_test_add_func ("/gvariant/stack-builder-init", test_stack_builder_init);
|
||||
g_test_add_func ("/gvariant/stack-dict-init", test_stack_dict_init);
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user