зеркало из https://github.com/microsoft/STL.git
Fix null function check for `move_only_function` (#3038)
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
This commit is contained in:
Родитель
ed0e3e5ad9
Коммит
39b29dd049
|
@ -1383,20 +1383,19 @@ public:
|
||||||
// (The RTTI savings may be significant as with lambdas and binds there may be many distinct callable types.
|
// (The RTTI savings may be significant as with lambdas and binds there may be many distinct callable types.
|
||||||
// Here we don't have a distinct wrapper class for each callable type, only distinct functions when needed.)
|
// Here we don't have a distinct wrapper class for each callable type, only distinct functions when needed.)
|
||||||
|
|
||||||
|
// _Move and _Destroy are nullptr if trivial. Besides being an optimization, this enables assigning an
|
||||||
|
// empty function from a DLL that is unloaded later, and then safely moving/destroying that empty function.
|
||||||
|
|
||||||
// Calls target
|
// Calls target
|
||||||
typename _Invoke_t<_Noexcept>::_Call _Invoke;
|
typename _Invoke_t<_Noexcept>::_Call _Invoke;
|
||||||
// Moves the data, including pointer to "vtable", AND destroys old data (not resetting its "vtable")
|
// Moves the data, including pointer to "vtable", AND destroys old data (not resetting its "vtable").
|
||||||
|
// nullptr if we can trivially move two pointers.
|
||||||
void(__stdcall* _Move)(_Move_only_function_data&, _Move_only_function_data&) _NOEXCEPT_FNPTR;
|
void(__stdcall* _Move)(_Move_only_function_data&, _Move_only_function_data&) _NOEXCEPT_FNPTR;
|
||||||
// Destroys data (not resetting its "vtable")
|
// Destroys data (not resetting its "vtable").
|
||||||
|
// nullptr if destruction is a no-op.
|
||||||
void(__stdcall* _Destroy)(_Move_only_function_data&) _NOEXCEPT_FNPTR;
|
void(__stdcall* _Destroy)(_Move_only_function_data&) _NOEXCEPT_FNPTR;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr _Impl_t _Null_move_only_function = {
|
|
||||||
_Function_not_callable<_Rx, _Types...>,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
_Move_only_function_data _Data;
|
_Move_only_function_data _Data;
|
||||||
|
|
||||||
_Move_only_function_base() noexcept = default; // leaves fields uninitialized
|
_Move_only_function_base() noexcept = default; // leaves fields uninitialized
|
||||||
|
@ -1407,12 +1406,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Construct_with_null() noexcept {
|
void _Construct_with_null() noexcept {
|
||||||
_Data._Impl = &_Null_move_only_function;
|
_Data._Impl = nullptr;
|
||||||
_Data._Set_large_fn_ptr(nullptr); // initialize, since we'll be copying it
|
_Data._Set_large_fn_ptr(nullptr); // initialize, since we'll be copying it
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Reset_to_null() noexcept {
|
void _Reset_to_null() noexcept {
|
||||||
_Data._Impl = &_Null_move_only_function;
|
_Data._Impl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _Vt, class _VtInvQuals, class... _CTypes>
|
template <class _Vt, class _VtInvQuals, class... _CTypes>
|
||||||
|
@ -1426,14 +1425,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _Checked_destroy(_Move_only_function_data& _Data) noexcept {
|
static void _Checked_destroy(_Move_only_function_data& _Data) noexcept {
|
||||||
const auto _Impl = static_cast<const _Impl_t*>(_Data._Impl);
|
const auto _Impl = _Get_impl(_Data);
|
||||||
if (_Impl->_Destroy) {
|
if (_Impl->_Destroy) {
|
||||||
_Impl->_Destroy(_Data);
|
_Impl->_Destroy(_Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _Checked_move(_Move_only_function_data& _Data, _Move_only_function_data& _Src) noexcept {
|
static void _Checked_move(_Move_only_function_data& _Data, _Move_only_function_data& _Src) noexcept {
|
||||||
const auto _Impl = static_cast<const _Impl_t*>(_Src._Impl);
|
const auto _Impl = _Get_impl(_Src);
|
||||||
if (_Impl->_Move) {
|
if (_Impl->_Move) {
|
||||||
_Impl->_Move(_Data, _Src);
|
_Impl->_Move(_Data, _Src);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1447,8 +1446,9 @@ public:
|
||||||
// It is more efficient to do the reverse - this way no temporary storage for the old target will be used.
|
// It is more efficient to do the reverse - this way no temporary storage for the old target will be used.
|
||||||
// In some cases when some operations are trivial, it can be optimized,
|
// In some cases when some operations are trivial, it can be optimized,
|
||||||
// as the order change is unobservable, and everything is noexcept here.
|
// as the order change is unobservable, and everything is noexcept here.
|
||||||
const auto _Other_impl_move = static_cast<const _Impl_t*>(_Other._Data._Impl)->_Move;
|
const auto _This_impl = _Get_impl(_Data);
|
||||||
const auto _This_impl_destroy = static_cast<const _Impl_t*>(_Data._Impl)->_Destroy;
|
const auto _Other_impl_move = _Get_impl(_Other._Data)->_Move;
|
||||||
|
const auto _This_impl_destroy = _This_impl->_Destroy;
|
||||||
|
|
||||||
if (!_Other_impl_move) {
|
if (!_Other_impl_move) {
|
||||||
// Move is trivial, destroy first if needed
|
// Move is trivial, destroy first if needed
|
||||||
|
@ -1462,7 +1462,13 @@ public:
|
||||||
} else {
|
} else {
|
||||||
// General case involving a temporary
|
// General case involving a temporary
|
||||||
_Move_only_function_data _Tmp;
|
_Move_only_function_data _Tmp;
|
||||||
_Checked_move(_Tmp, _Data);
|
|
||||||
|
if (_This_impl->_Move) {
|
||||||
|
_This_impl->_Move(_Tmp, _Data);
|
||||||
|
} else {
|
||||||
|
_Function_move_large(_Tmp, _Data);
|
||||||
|
}
|
||||||
|
|
||||||
_Other_impl_move(_Data, _Other._Data);
|
_Other_impl_move(_Data, _Other._Data);
|
||||||
_This_impl_destroy(_Tmp);
|
_This_impl_destroy(_Tmp);
|
||||||
}
|
}
|
||||||
|
@ -1478,7 +1484,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD bool _Is_null() const noexcept {
|
_NODISCARD bool _Is_null() const noexcept {
|
||||||
return _Data._Impl == &_Null_move_only_function;
|
return _Data._Impl == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _Vt>
|
template <class _Vt>
|
||||||
|
@ -1487,7 +1493,18 @@ public:
|
||||||
|| sizeof(_Vt) > _Move_only_function_data::_Buf_size<_Vt> || !is_nothrow_move_constructible_v<_Vt>;
|
|| sizeof(_Vt) > _Move_only_function_data::_Buf_size<_Vt> || !is_nothrow_move_constructible_v<_Vt>;
|
||||||
|
|
||||||
_NODISCARD auto _Get_invoke() const noexcept {
|
_NODISCARD auto _Get_invoke() const noexcept {
|
||||||
return static_cast<const _Impl_t*>(_Data._Impl)->_Invoke;
|
return _Get_impl(_Data)->_Invoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD static const _Impl_t* _Get_impl(const _Move_only_function_data& _Data) noexcept {
|
||||||
|
static constexpr _Impl_t _Null_move_only_function = {
|
||||||
|
_Function_not_callable<_Rx, _Types...>,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto _Ret = static_cast<const _Impl_t*>(_Data._Impl);
|
||||||
|
return _Ret ? _Ret : &_Null_move_only_function;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class _Vt, class _VtInvQuals>
|
template <class _Vt, class _VtInvQuals>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче