deprecate G_VALUE_COLLECT and G_VALUE_LCOPY
Submitted by Allison (desrt)
Link to original bug (#701195)
Description
Some more low-hanging GObject performance fruit...
These macros (in addition to being ugly in both use and implementation) are also slow: they force a copy.
Using G_VALUE_COLLECT() invariably looks like so (even using the 'fast' version):
GValue value = { 0, } G_VALUE_COLLECT_INIT (&value, ...) give_value_somewhere (obj, "foo", &value); g_value_unset (&value);
ie: we make a copy of the user's passed-in argument inside of the GValue, then free that copy.
G_VALUE_LCOPY(), just the same, but the other way around:
GValue value = { 0, } get_value_from_somewhere (&value); G_VALUE_LCOPY (&value, ...); g_value_unset (&value);
ie: we make a copy of our own GValue data to give to the user, only to free our own data later.
We could fix this in the first case by creating a special degenerate type of GValue that does not own its own data, but is dependent on the passed-in data remaining valid. This would be true, because the GValue would only exist for the duration of our stackframe and we're using a value passed from the user (and destroying before we ever return). This has one very small potential safety issue: if the user is passing us back a string from our own internal state and we destroy that string in a set_property() handler and then try to access the user's string, we could have trouble. I'm willing to believe that there is such bad code 'in the wild' that does this, but it would already have this problem on its _set_foo() C API, so that code should be fixed anyway.
We could fix the second issue by having a variant of G_VALUE_LCOPY() that destroys the GValue given to it and steals its contents to give to the user. There is absolutely no potential safety/compatibility issue here.
Meanwhile, we should stop doing the weird "copy pointers into an array according to format string and pass the array into a function" business and just pass around 'va_list *' directly. GVariant has been doing this since it existed for g_variant_new() and g_variant_get() so we can be pretty sure that compiler support for it is up to snuff these days (and indeed, C99 explicitly specifies that this must be supported).
The only problem is that GTypeValueTable doesn't have any extra room.... the best thing I can think to do (which is pretty bad) is to support this new mode of operation via having NULL 'collect_format' and 'lcopy_format' strings, but still having the 'collect_value' and 'lcopy_value' function pointers (as a way of indicating that we're doing the new style). The new function pointers would, unfortunately, need to have an incompatible type (or use gpointer in the vtable). This is the ugly part of this change....
We could also assume that nobody does cross-ABI struct embedding of GTypeValueTable (which would be ridiculous) and mostly only uses it in a static-allocation or stack-allocation situation. We could then expand the struct and add some extra fields that we only use if we discover collect_format and lcopy_format to be NULL.
Then we can add new C APIs (not macros) for using these new functions with the no-copy semantics. We can emulate the old from the new and the new from the old both ways (although with additional copies) fairly well. The only concern I have is about the emulation of the new interface for collection using the old collect_value API -- the new interface wants to return a GValue that does not need to be unset, and it's difficult to imagine how we could do this based on the old API. Perhaps we should use a flag on the GValue itself to indicate that unset() should be a no-op and still say that you always must call it (which would make this all bind nicer as well, ha).