Add move assignment and move constructor to Variant.
This PR adds move assignment and move constructors to Variant. With them, slightly faster code can be generated when working with variants, especially in cases of generated code from macros and templates, such as from virtual methods.
This PR also adds _to_variant helper functions to gdvirtual.gen.inc to work around an MSVC bug (explained below).
On move semantics
Move semantics help the compiler generate faster code. Take this example:
Variant variant = make_variant(); // imagine this returns a String variant
(for the sake of the example, let's ignore that this specific code may generate in-place construction instead) Normally, this would generate the following pseudo assembly / execution dynamic:
CALL make_variant
CALL Variant.operator=(Variant&)
MEMCPY
DYNAMIC JUMP
--> CALL String.reference
CALL ~Variant
DYNAMIC JUMP ; to variant.string
--> CALL String.dereference
Using move semantics, this can be improved to:
CALL make_variant
CALL Variant.operator=(Variant&&)
MEMCPY
ASSIGN
CALL ~Variant
DYNAMIC JUMP ; to variant.nil
So, most importantly, calls to String.reference and String.dereference can be avoided, by transferring ownership instead of making a copy. Additionally, the dynamic jump at the end is known to land on NIL which may lead to additional improvements of performance through branch prediction, and could even be skipped entirely if known statically (though this is not the case in the codebase right now).
Move semantics may be chosen in other places automatically if the compiler recognizes it to be a compatible situation, to improve performance. One other example where this may lead to observable speedups is the SWAP macro when used on Variant arguments.
Caveats
MSVC appears to have a bug in selecting .operator Variant() in some specific combination of move constructors, macro calls and template functions. Other compilers do not have this problem. You can view an example trigger of this bug here (from this workflow run):
Error: .\servers/audio/audio_effect.h(43): error C2440: '<function-style-cast>': cannot convert from 'GDExtensionPtr<AudioFrame>' to 'Variant'
.\servers/audio/audio_effect.h(43): note: 'Variant::Variant': ambiguous call to overloaded function
.\core/variant/variant.h(825): note: could be 'Variant::Variant(const Variant &)'
.\core/variant/variant.h(826): note: or 'Variant::Variant(Variant &&)'
.\core/variant/variant.h(455): note: or 'Variant::Variant(bool)'
.\servers/audio/audio_effect.h(43): note: while trying to match the argument list '(GDExtensionPtr<AudioFrame>)'
scons: *** [platform\windows\display_server_windows.windows.template_release.x86_64.obj] Error 2
I have introduced the SFINAE supported functions _to_variant to work around this bug. The functions are designed to help the compiler select .operator Variant() explicitly when the function is offered. They will be inlined and thus will not generate worse code in other compilers.
Why is msvc still a garbage fire...
Do you know if there is any bug open for this on the msvc side ? Could be nice to at least have a link with the PR here to be able to check progress on their side ( if any ..). Maybe open one if there is none ?
I did not find anything on a cursory search. Opening one makes sense, though I don't know if it would help the MSVC team without an MRP, given the complexity of this repo.
Thanks!