@@ -999,6 +999,25 @@ public:
999999#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES
10001000 }
10011001
1002+ bool _Local () const noexcept { // test for locally stored copy of object
1003+ return _Getimpl () == static_cast <const void *>(&_Mystorage);
1004+ }
1005+
1006+ _Ptrt* _Getimpl () const noexcept { // get pointer to object
1007+ return _Mystorage._Ptrs [_Small_object_num_ptrs - 1 ];
1008+ }
1009+
1010+ void _Set (_Ptrt* _Ptr) noexcept { // store pointer to object
1011+ _Mystorage._Ptrs [_Small_object_num_ptrs - 1 ] = _Ptr;
1012+ }
1013+
1014+ void _Tidy () noexcept {
1015+ if (!_Empty ()) { // destroy callable object and maybe delete it
1016+ _Getimpl ()->_Delete_this (!_Local ());
1017+ _Set (nullptr );
1018+ }
1019+ }
1020+
10021021protected:
10031022 template <class _Fx , class _Function >
10041023 using _Enable_if_callable_t = enable_if_t <conjunction_v<negation<is_same<_Remove_cvref_t<_Fx>, _Function>>,
@@ -1066,13 +1085,6 @@ protected:
10661085 }
10671086 }
10681087
1069- void _Tidy () noexcept {
1070- if (!_Empty ()) { // destroy callable object and maybe delete it
1071- _Getimpl ()->_Delete_this (!_Local ());
1072- _Set (nullptr );
1073- }
1074- }
1075-
10761088 void _Swap (_Func_class& _Right) noexcept { // swap contents with contents of _Right
10771089 if (!_Local () && !_Right._Local ()) { // just swap pointers
10781090 _Ptrt* _Temp = _Getimpl ();
@@ -1097,10 +1109,6 @@ protected:
10971109#endif // _HAS_STATIC_RTTI
10981110
10991111private:
1100- bool _Local () const noexcept { // test for locally stored copy of object
1101- return _Getimpl () == static_cast <const void *>(&_Mystorage);
1102- }
1103-
11041112 union _Storage { // storage for small objects (basic_string is small)
11051113 max_align_t _Dummy1; // for maximum alignment
11061114 char _Dummy2[_Space_size]; // to permit aliasing
@@ -1109,13 +1117,6 @@ private:
11091117
11101118 _Storage _Mystorage;
11111119 enum { _EEN_IMPL = _Small_object_num_ptrs - 1 }; // helper for expression evaluator
1112- _Ptrt* _Getimpl () const noexcept { // get pointer to object
1113- return _Mystorage._Ptrs [_Small_object_num_ptrs - 1 ];
1114- }
1115-
1116- void _Set (_Ptrt* _Ptr) noexcept { // store pointer to object
1117- _Mystorage._Ptrs [_Small_object_num_ptrs - 1 ] = _Ptr;
1118- }
11191120};
11201121
11211122template <class _Tx >
@@ -1423,6 +1424,12 @@ template <class _Rx, class... _Types>
14231424 _STL_UNREACHABLE; // no return value available for "continue on error"
14241425}
14251426
1427+ template <class _Rx , bool _Noex, class ... _Types>
1428+ [[noreturn]] _Rx __stdcall _Function_old_not_callable (const _Move_only_function_data&, _Types&&...)
1429+ noexcept (_Noex) /* terminates if _Noex */ {
1430+ _Xbad_function_call ();
1431+ }
1432+
14261433template <class _Vt , class _VtInvQuals , class _Rx , bool _Noex, class ... _Types>
14271434_NODISCARD _Rx __stdcall _Function_inv_small (const _Move_only_function_data& _Self, _Types&&... _Args) noexcept (_Noex) {
14281435 if constexpr (is_void_v<_Rx>) {
@@ -1441,6 +1448,18 @@ _NODISCARD _Rx __stdcall _Function_inv_large(const _Move_only_function_data& _Se
14411448 }
14421449}
14431450
1451+ template <class _Fn , class _Rx , bool _Noex, class ... _Types>
1452+ _NODISCARD _Rx __stdcall _Function_inv_old_large (const _Move_only_function_data& _Self, _Types&&... _Args)
1453+ noexcept (_Noex) {
1454+ return _Self._Large_fn_ptr <_Fn>()->_Do_call (_STD forward<_Types>(_Args)...);
1455+ }
1456+
1457+ template <class _Fn , class _Rx , bool _Noex, class ... _Types>
1458+ _NODISCARD _Rx __stdcall _Function_inv_old_small (const _Move_only_function_data& _Self, _Types&&... _Args)
1459+ noexcept (_Noex) {
1460+ return _Self._Small_fn_ptr <_Fn>()->_Do_call (_STD forward<_Types>(_Args)...);
1461+ }
1462+
14441463template <class _Vt >
14451464void __stdcall _Function_move_small (_Move_only_function_data& _Self, _Move_only_function_data& _Src) noexcept {
14461465 const auto _Src_fn_ptr = _Src._Small_fn_ptr <_Vt>();
@@ -1458,6 +1477,14 @@ inline void __stdcall _Function_move_large(_Move_only_function_data& _Self, _Mov
14581477 _CSTD memcpy (&_Self._Data , &_Src._Data , _Minimum_function_size); // Copy Impl* and functor data
14591478}
14601479
1480+ template <class _Fn >
1481+ void __stdcall _Function_move_old_small (_Move_only_function_data& _Self, _Move_only_function_data& _Src) noexcept {
1482+ _Fn* const _Old_fn_impl = _Src._Small_fn_ptr <_Fn>();
1483+ _Old_fn_impl->_Move (_Self._Buf_ptr <void *>());
1484+ _Old_fn_impl->_Delete_this (false );
1485+ _Self._Impl = _Src._Impl ;
1486+ }
1487+
14611488template <class _Vt >
14621489void __stdcall _Function_destroy_small (_Move_only_function_data& _Self) noexcept {
14631490 _Self._Small_fn_ptr <_Vt>()->~_Vt ();
@@ -1467,6 +1494,22 @@ inline void __stdcall _Function_deallocate_large_default_aligned(_Move_only_func
14671494 ::operator delete (_Self._Large_fn_ptr <void >());
14681495}
14691496
1497+ template <class _Fn >
1498+ inline void __stdcall _Function_destroy_old_large (_Move_only_function_data& _Self) noexcept {
1499+ _Self._Large_fn_ptr <_Fn>()->_Delete_this (true );
1500+ }
1501+
1502+ template <class _Fn >
1503+ inline void __stdcall _Function_destroy_old_small_as_large (_Move_only_function_data& _Self) noexcept {
1504+ _Fn* const _Old_fn_impl = _Self._Large_fn_ptr <_Fn>();
1505+ _Old_fn_impl->_Delete_this (false );
1506+ ::operator delete (static_cast <void *>(_Old_fn_impl));
1507+ }
1508+ template <class _Fn >
1509+ inline void __stdcall _Function_destroy_old_small (_Move_only_function_data& _Self) noexcept {
1510+ _Self._Small_fn_ptr <_Fn>()->_Delete_this (false );
1511+ }
1512+
14701513template <size_t _Align>
14711514void __stdcall _Function_deallocate_large_overaligned (_Move_only_function_data& _Self) noexcept {
14721515 _STL_INTERNAL_STATIC_ASSERT (_Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__);
@@ -1564,6 +1607,14 @@ public:
15641607 void (__stdcall* _Destroy)(_Move_only_function_data&) _NOEXCEPT_FNPTR;
15651608 };
15661609
1610+ enum class _Impl_kind {
1611+ _Usual,
1612+ _Old_fn_null,
1613+ _Old_fn_large,
1614+ _Old_fn_small_as_large,
1615+ _Old_fn_small,
1616+ };
1617+
15671618 _Move_only_function_data _Data;
15681619
15691620 _Move_only_function_base () noexcept = default ; // leaves fields uninitialized
@@ -1577,9 +1628,38 @@ public:
15771628 _Data._Impl = nullptr ;
15781629 }
15791630
1631+ template <class _Vt , class _VtInvQuals , class _Fn >
1632+ void _Construct_with_old_fn (_Fn&& _Func) {
1633+ const auto _Old_fn_impl = _Func._Getimpl ();
1634+ if (_Old_fn_impl == nullptr ) {
1635+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, _VtInvQuals>();
1636+ } else if (_Func._Local ()) {
1637+ if constexpr (alignof (max_align_t ) == alignof (void *)) {
1638+ // 64-bit target, can put small function into small move_only_function directly
1639+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, _VtInvQuals>();
1640+ _Old_fn_impl->_Move (_Data._Buf_ptr <void *>());
1641+ _Func._Tidy ();
1642+ } else {
1643+ // 32-bit target, cannot small function into small move_only_function directly
1644+ // due to potentially not enough alignment. Allocate large function
1645+ void * _Where = ::operator new ((_Small_object_num_ptrs - 1 ) * sizeof (void *));
1646+ _Old_fn_impl->_Move (_Where);
1647+ _Func._Tidy ();
1648+
1649+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, _VtInvQuals>();
1650+ _Data._Set_large_fn_ptr (_Where);
1651+ }
1652+ } else {
1653+ // Just take ownership of the inner impl pointer
1654+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, _VtInvQuals>();
1655+ _Data._Set_large_fn_ptr (_Old_fn_impl);
1656+ _Func._Set (nullptr );
1657+ }
1658+ }
1659+
15801660 template <class _Vt , class _VtInvQuals , class ... _CTypes>
15811661 void _Construct_with_fn (_CTypes&&... _Args) {
1582- _Data._Impl = _Create_impl_ptr<_Vt, _VtInvQuals>();
1662+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _VtInvQuals>();
15831663 if constexpr (_Large_function_engaged<_Vt>) {
15841664 _Data._Set_large_fn_ptr (_STD _Function_new_large<_Vt>(_STD forward<_CTypes>(_Args)...));
15851665 } else {
@@ -1670,10 +1750,29 @@ public:
16701750 return _Ret ? _Ret : &_Null_move_only_function;
16711751 }
16721752
1673- template <class _Vt , class _VtInvQuals >
1753+ template <_Impl_kind _Kind, class _Vt , class _VtInvQuals >
16741754 _NODISCARD static constexpr _Impl_t _Create_impl () noexcept {
16751755 _Impl_t _Impl{};
1676- if constexpr (_Large_function_engaged<_Vt>) {
1756+ if constexpr (_Kind != _Impl_kind::_Usual) {
1757+ using _Fn = remove_pointer_t <decltype (_STD declval<_Vt>()._Getimpl ())>;
1758+ if constexpr (_Kind == _Impl_kind::_Old_fn_null) {
1759+ _Impl._Invoke = _Function_old_not_callable<_Rx, _Noexcept, _Types...>;
1760+ _Impl._Move = nullptr ;
1761+ _Impl._Destroy = nullptr ;
1762+ } else if constexpr (_Kind == _Impl_kind::_Old_fn_large) {
1763+ _Impl._Invoke = _Function_inv_old_large<_Fn, _Rx, _Noexcept, _Types...>;
1764+ _Impl._Move = nullptr ;
1765+ _Impl._Destroy = _Function_destroy_old_large<_Fn>;
1766+ } else if constexpr (_Kind == _Impl_kind::_Old_fn_small_as_large) {
1767+ _Impl._Invoke = _Function_inv_old_large<_Fn, _Rx, _Noexcept, _Types...>;
1768+ _Impl._Move = nullptr ;
1769+ _Impl._Destroy = _Function_destroy_old_small_as_large<_Fn>;
1770+ } else if constexpr (_Kind == _Impl_kind::_Old_fn_small) {
1771+ _Impl._Invoke = _Function_inv_old_small<_Fn, _Rx, _Noexcept, _Types...>;
1772+ _Impl._Move = _Function_move_old_small<_Fn>;
1773+ _Impl._Destroy = _Function_destroy_old_small<_Fn>;
1774+ }
1775+ } else if constexpr (_Large_function_engaged<_Vt>) {
16771776 _Impl._Invoke = _Function_inv_large<_Vt, _VtInvQuals, _Rx, _Noexcept, _Types...>;
16781777 _Impl._Move = nullptr ;
16791778
@@ -1708,9 +1807,9 @@ public:
17081807 return _Impl;
17091808 }
17101809
1711- template <class _Vt , class _VtInvQuals >
1810+ template <_Impl_kind _Kind, class _Vt , class _VtInvQuals >
17121811 _NODISCARD static const _Impl_t* _Create_impl_ptr () noexcept {
1713- static constexpr _Impl_t _Impl = _Create_impl<_Vt, _VtInvQuals>();
1812+ static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _VtInvQuals>();
17141813 return &_Impl;
17151814 }
17161815};
@@ -1965,16 +2064,20 @@ public:
19652064 using _Vt = decay_t <_Fn>;
19662065 static_assert (is_constructible_v<_Vt, _Fn>, " _Vt should be constructible from _Fn. "
19672066 " (N4950 [func.wrap.move.ctor]/6)" );
2067+ using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
19682068
1969- if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> || _Is_specialization_v<_Vt, move_only_function>) {
1970- if (_Callable == nullptr ) {
1971- this ->_Reset_to_null ();
1972- return ;
2069+ if constexpr (_Is_specialization_v<_Vt, function>) {
2070+ this ->template _Construct_with_old_fn <_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable));
2071+ } else {
2072+ if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt>
2073+ || _Is_specialization_v<_Vt, move_only_function>) {
2074+ if (_Callable == nullptr ) {
2075+ this ->_Reset_to_null ();
2076+ return ;
2077+ }
19732078 }
2079+ this ->template _Construct_with_fn <_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable));
19742080 }
1975-
1976- using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
1977- this ->template _Construct_with_fn <_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable));
19782081 }
19792082
19802083 template <class _Fn , class ... _CTypes>
0 commit comments