1

Background

I'm using GLib and variants.

I have this scenario where I want to get the value deep inside a variant.

The initial variant, changed_properties has the format a{sv}.

// Example 1
/* GVariant *variant = g_variant_get_variant(
        g_variant_get_child_value(g_variant_get_child_value(changed_properties, 0), 1));
*/

GVariant *changed_property = g_variant_get_child_value(changed_properties, 0);

// Example 2
GVariant *changed_property_variant = g_variant_get_variant(g_variant_get_child_value(changed_property, 1));
// Unref only frees g_variant_get_variant

// Example 3
GVariant *changed_property_variant_child = g_variant_get_child_value(changed_property, 1);

GVariant *changed_property_variant = g_variant_get_variant(changed_property_variant_child);

// Unref the objects and let reference counter get rid of used memory
g_variant_unref(changed_property_variant);
g_variant_unref(changed_property_variant_child);

What I understand

In my understanding, to extract v (which is a variant), I have first to extract the first {sv} from the array of sv dictionaries. In Example 3, I perform this in the first function call of g_variant_get_child_value(changed_properties, 0) after the commented code in Example 1.

Now I'm left with a resulting variant in the form of {sv}. To extract the variant, I have to yet again call g_variant_get_child_value(changed_property, 1) (Where index 0 is the string and index 1 is the variant in {sv} dictionary.

The issue

The issue appears when calling functions like in Example 1 and Example 2. All the references of the memory obtained from g_variant_get_child_value(), g_variant_get_variant(), except for the last call which puts the reference in the variable, are lost and cannot be unrefferenced (as in Example 3).

The question

So my question is: How can one get to the depth of v and its contents without creating so many GVariant objects and handle so much memory through references?

ptomato
  • 56,175
  • 13
  • 112
  • 165
bem22
  • 276
  • 1
  • 14
  • 1
    GVariant is part of glib, not glibc; those are completely different libraries. – mark4o Oct 14 '21 at 22:46
  • Thanks, but the memory rmanagement mechanism is quite specific to C – bem22 Oct 15 '21 at 11:09
  • glibc and GLib are different libraries. It’s not that glibc is a C binding of GLib or anything like that. They provide completely different APIs and are provided by different projects. – Philip Withnall Oct 18 '21 at 09:57

1 Answers1

1

If you’ve been provided with an a{sv} you are likely wanting to look up a particular key (an a{sv} is the GVariant/D-Bus representation of a key-value dictionary).

To do so, use GVariantDict, which allows indexed access by string key:

g_auto(GVariantDict) dict = G_VARIANT_DICT_INIT (changed_properties);
guint value;
if (!g_variant_dict_lookup (&dict, "key-to-look-up", "u", &value))
  g_error ("key not found");
// value from v is now in `value`

You will need to know the type of the value in advance, and pass that as the format string (third argument) to g_variant_dict_lookup().

Philip Withnall
  • 5,293
  • 14
  • 28
  • This is cool. I am going to test it tomorrow. I wonder what time complexity the lookup has. With the provided examples I have O(1) time complexity, but I have to handle those ref counts. I'm wondering if there is another way. Good pointing out this. Many thanks. – bem22 Oct 18 '21 at 23:24
  • 1
    `G_VARIANT_DICT_INIT` is O(N) in the number of changed properties. `g_variant_dict_lookup()` is amortised O(1). GVariant is in general fast enough that you won’t be able to see its performance impact in a trace unless you’re running it in a tight loop or parsing tens of megabytes of data. – Philip Withnall Oct 19 '21 at 13:21
  • I'm parsing some sensors at 120 samples/second. I was leaking memory from this before and I was filling up about 150mb /minute. I will test this soon. – bem22 Oct 19 '21 at 15:57
  • Let me know how it goes :) – Philip Withnall Oct 19 '21 at 22:03