Unwrap call of function passed to move_only_function by AlexGuteniev · Pull Request #5808 · microsoft/STL (original) (raw)
Towards #5504.
One of the parts of the issue that can be addressed without having copyable_function.
✅ Coverage
Added just copy counter to see that the optimization works. It is copied zero times due to some core language optimization, but without the optimization it is copied once in the cases where it was missing.
Also added allocation counters to see that the other part of the optimization works.
Exercise different wrapping and also null functions.
⚙️ Optimization
Extract the inner _Func_impl / _Func_impl_no_alloc and use directly it without the containing function. This both gets call unwrapping and allocation avoidance.
⚠️ ABI and alignment issues
This change is only complicated in the current ABI. If in a future ABI it is possible to implement function the same way that move_only_function is implemented, things would be way easier.
For 32-bit we can't easily avoid allocation of small function. The buffer of function is aligned to max_align_t and the buffer inside move_only_function is aligned only as void* if it is next to vTable. move_only_function can contain objects of max_align_t alignment, but in that case the buffer size would be smaller. As type erasure already happened by the time we have function, we can't query actual size or alignment.
We probably could change move_only_function to make is emulated vtable the last pointer instead of the first, as we're not ABI-bound for /std:c++latest yet. But it doesn't look like a good idea, considering other, more common move_only_function usage.
❄️ Special cases
We throw bad_function_call, and don't make move_only_function containing null function null itself. Because the Standard is spelled out this way currently.
If function is constructed inside move_only_function using in_place_type, this optimization is not engaged.
Also see #5806