@@ -971,6 +971,11 @@ private:
971971 _Callable _Callee;
972972};
973973
974+ #if _HAS_CXX23
975+ template <class _Rx, bool _Noexcept, class... _Types>
976+ class _Move_only_function_base;
977+ #endif // _HAS_CXX23
978+
974979template <class _Ret, class... _Types>
975980class _Func_class : public _Arg_types<_Types...> {
976981public:
@@ -1097,6 +1102,10 @@ protected:
10971102#endif // _HAS_STATIC_RTTI
10981103
10991104private:
1105+ #if _HAS_CXX23
1106+ friend _Move_only_function_base<_Ret, false, _Types...>;
1107+ #endif // _HAS_CXX23
1108+
11001109 bool _Local() const noexcept { // test for locally stored copy of object
11011110 return _Getimpl() == static_cast<const void*>(&_Mystorage);
11021111 }
@@ -1370,6 +1379,8 @@ _NODISCARD bool operator!=(nullptr_t, const function<_Fty>& _Other) noexcept {
13701379#endif // !_HAS_CXX20
13711380
13721381#if _HAS_CXX23
1382+ enum class _Function_storage_mode { _Small, _Large };
1383+
13731384// _Move_only_function_data is defined as an array of pointers.
13741385// The first element is always a pointer to _Move_only_function_base::_Impl_t; it emulates a vtable pointer.
13751386// The other pointers are used as storage for a small functor;
@@ -1392,16 +1403,15 @@ union alignas(max_align_t) _Move_only_function_data {
13921403 return &_Data + _Buf_offset<_Fn>;
13931404 }
13941405
1395- template <class _Fn>
1396- _NODISCARD _Fn* _Small_fn_ptr() const noexcept {
1397- // cast away const to avoid complication of const propagation to here;
1398- // const correctness is still enforced by _Move_only_function_call specializations.
1399- return static_cast<_Fn*>(const_cast<_Move_only_function_data*>(this)->_Buf_ptr<_Fn>());
1400- }
1401-
1402- template <class _Fn>
1403- _NODISCARD _Fn* _Large_fn_ptr() const noexcept {
1404- return static_cast<_Fn*>(_Pointers[1]);
1406+ template <class _Fn, _Function_storage_mode _Mode>
1407+ _NODISCARD _Fn* _Fn_ptr() const noexcept {
1408+ if constexpr (_Mode == _Function_storage_mode::_Small) {
1409+ // cast away const to avoid complication of const propagation to here;
1410+ // const correctness is still enforced by _Move_only_function_call specializations.
1411+ return static_cast<_Fn*>(const_cast<_Move_only_function_data*>(this)->_Buf_ptr<_Fn>());
1412+ } else {
1413+ return static_cast<_Fn*>(_Pointers[1]);
1414+ }
14051415 }
14061416
14071417 void _Set_large_fn_ptr(void* const _Value) noexcept {
@@ -1423,27 +1433,28 @@ template <class _Rx, class... _Types>
14231433 _STL_UNREACHABLE; // no return value available for "continue on error"
14241434}
14251435
1426- template <class _Vt, class _VtInvQuals, class _Rx, bool _Noex, class... _Types>
1427- _NODISCARD _Rx __stdcall _Function_inv_small(const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) {
1428- if constexpr (is_void_v<_Rx>) {
1429- (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...);
1430- } else {
1431- return _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...);
1432- }
1436+ template <class _Rx, class... _Types>
1437+ [[noreturn]] _Rx __stdcall _Function_old_not_callable(const _Move_only_function_data&, _Types&&...) {
1438+ _Xbad_function_call();
14331439}
14341440
1435- template <class _Vt, class _VtInvQuals, class _Rx, bool _Noex, class... _Types>
1436- _NODISCARD _Rx __stdcall _Function_inv_large (const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) {
1441+ template <class _Vt, class _VtInvQuals, _Function_storage_mode _Mode, class _Rx, bool _Noex, class... _Types>
1442+ _NODISCARD _Rx __stdcall _Function_inv (const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) {
14371443 if constexpr (is_void_v<_Rx>) {
1438- (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr <_Vt>()), _STD forward<_Types>(_Args)...);
1444+ (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Fn_ptr <_Vt, _Mode >()), _STD forward<_Types>(_Args)...);
14391445 } else {
1440- return _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr <_Vt>()), _STD forward<_Types>(_Args)...);
1446+ return _STD invoke(static_cast<_VtInvQuals>(*_Self._Fn_ptr <_Vt, _Mode >()), _STD forward<_Types>(_Args)...);
14411447 }
14421448}
14431449
1450+ template <class _Fn, _Function_storage_mode _Mode, class _Rx, class... _Types>
1451+ _NODISCARD _Rx __stdcall _Function_inv_old(const _Move_only_function_data& _Self, _Types&&... _Args) {
1452+ return _Self._Fn_ptr<_Fn, _Mode>()->_Do_call(_STD forward<_Types>(_Args)...);
1453+ }
1454+
14441455template <class _Vt>
14451456void __stdcall _Function_move_small(_Move_only_function_data& _Self, _Move_only_function_data& _Src) noexcept {
1446- const auto _Src_fn_ptr = _Src._Small_fn_ptr <_Vt>();
1457+ const auto _Src_fn_ptr = _Src._Fn_ptr <_Vt, _Function_storage_mode::_Small >();
14471458 ::new (_Self._Buf_ptr<_Vt>()) _Vt(_STD move(*_Src_fn_ptr));
14481459 _Src_fn_ptr->~_Vt();
14491460 _Self._Impl = _Src._Impl;
@@ -1458,28 +1469,57 @@ inline void __stdcall _Function_move_large(_Move_only_function_data& _Self, _Mov
14581469 _CSTD memcpy(&_Self._Data, &_Src._Data, _Minimum_function_size); // Copy Impl* and functor data
14591470}
14601471
1472+ #ifdef _WIN64
1473+ template <class _Fn>
1474+ void __stdcall _Function_move_old_small(_Move_only_function_data& _Self, _Move_only_function_data& _Src) noexcept {
1475+ _Fn* const _Old_fn_impl = _Src._Fn_ptr<_Fn, _Function_storage_mode::_Small>();
1476+ _Old_fn_impl->_Move(_Self._Buf_ptr<void*>());
1477+ _Old_fn_impl->_Delete_this(false);
1478+ _Self._Impl = _Src._Impl;
1479+ }
1480+ #endif // ^^^ 64-bit ^^^
1481+
14611482template <class _Vt>
14621483void __stdcall _Function_destroy_small(_Move_only_function_data& _Self) noexcept {
1463- _Self._Small_fn_ptr <_Vt>()->~_Vt();
1484+ _Self._Fn_ptr <_Vt, _Function_storage_mode::_Small >()->~_Vt();
14641485}
14651486
14661487inline void __stdcall _Function_deallocate_large_default_aligned(_Move_only_function_data& _Self) noexcept {
1467- ::operator delete(_Self._Large_fn_ptr<void>());
1488+ ::operator delete(_Self._Fn_ptr<void, _Function_storage_mode::_Large>());
1489+ }
1490+
1491+ template <class _Fn>
1492+ void __stdcall _Function_destroy_old_large(_Move_only_function_data& _Self) noexcept {
1493+ _Self._Fn_ptr<_Fn, _Function_storage_mode::_Large>()->_Delete_this(true);
1494+ }
1495+
1496+ #ifdef _WIN64
1497+ template <class _Fn>
1498+ void __stdcall _Function_destroy_old_small(_Move_only_function_data& _Self) noexcept {
1499+ _Self._Fn_ptr<_Fn, _Function_storage_mode::_Small>()->_Delete_this(false);
1500+ }
1501+ #else // ^^^ 64-bit / 32-bit vvv
1502+ template <class _Fn>
1503+ void __stdcall _Function_destroy_old_small_as_large(_Move_only_function_data& _Self) noexcept {
1504+ _Fn* const _Old_fn_impl = _Self._Fn_ptr<_Fn, _Function_storage_mode::_Large>();
1505+ _Old_fn_impl->_Delete_this(false);
1506+ ::operator delete(static_cast<void*>(_Old_fn_impl));
14681507}
1508+ #endif // ^^^ 32-bit ^^^
14691509
14701510template <size_t _Align>
14711511void __stdcall _Function_deallocate_large_overaligned(_Move_only_function_data& _Self) noexcept {
14721512 _STL_INTERNAL_STATIC_ASSERT(_Align > __STDCPP_DEFAULT_NEW_ALIGNMENT__);
14731513#ifdef __cpp_aligned_new
1474- ::operator delete(_Self._Large_fn_ptr <void>(), align_val_t{_Align});
1514+ ::operator delete(_Self._Fn_ptr <void, _Function_storage_mode::_Large >(), align_val_t{_Align});
14751515#else // ^^^ defined(__cpp_aligned_new) / !defined(__cpp_aligned_new) vvv
1476- ::operator delete(_Self._Large_fn_ptr <void>());
1516+ ::operator delete(_Self._Fn_ptr <void, _Function_storage_mode::_Large >());
14771517#endif // ^^^ !defined(__cpp_aligned_new) ^^^
14781518}
14791519
14801520template <class _Vt>
14811521void __stdcall _Function_destroy_large(_Move_only_function_data& _Self) noexcept {
1482- const auto _Pfn = _Self._Large_fn_ptr <_Vt>();
1522+ const auto _Pfn = _Self._Fn_ptr <_Vt, _Function_storage_mode::_Large >();
14831523 _Pfn->~_Vt();
14841524#ifdef __cpp_aligned_new
14851525 if constexpr (alignof(_Vt) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {
@@ -1555,6 +1595,17 @@ public:
15551595 void(__stdcall* _Destroy)(_Move_only_function_data&) _NOEXCEPT_FNPTR;
15561596 };
15571597
1598+ enum class _Impl_kind {
1599+ _Usual = 0,
1600+ _Old_fn_null = 1,
1601+ _Old_fn_large = 2,
1602+ #ifdef _WIN64
1603+ _Old_fn_small = 3,
1604+ #else // ^^^ 64-bit / 32-bit vvv
1605+ _Old_fn_small_as_large = 4,
1606+ #endif // ^^^ 32-bit ^^^
1607+ };
1608+
15581609 _Move_only_function_data _Data;
15591610
15601611 _Move_only_function_base() noexcept = default; // leaves fields uninitialized
@@ -1568,9 +1619,40 @@ public:
15681619 _Data._Impl = nullptr;
15691620 }
15701621
1622+ template <class _Vt, class _Fn>
1623+ void _Construct_with_old_fn(_Fn&& _Func) {
1624+ const auto _Old_fn_impl = _Func._Getimpl();
1625+ if (_Old_fn_impl == nullptr) {
1626+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, void>();
1627+ } else if (_Func._Local()) {
1628+ #ifdef _WIN64
1629+ _STL_INTERNAL_STATIC_ASSERT(alignof(max_align_t) == alignof(void*));
1630+ // 64-bit target, can put small function into small move_only_function directly
1631+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, void>();
1632+ _Old_fn_impl->_Move(_Data._Buf_ptr<void*>());
1633+ _Func._Tidy();
1634+ #else // ^^^ 64-bit / 32-bit vvv
1635+ _STL_INTERNAL_STATIC_ASSERT(alignof(max_align_t) > alignof(void*));
1636+ // 32-bit target, cannot put small function into small move_only_function directly
1637+ // due to potentially not enough alignment. Allocate large function
1638+ void* _Where = ::operator new((_Small_object_num_ptrs - 1) * sizeof(void*));
1639+ _Old_fn_impl->_Move(_Where);
1640+ _Func._Tidy();
1641+
1642+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, void>();
1643+ _Data._Set_large_fn_ptr(_Where);
1644+ #endif // ^^^ 32-bit ^^^
1645+ } else {
1646+ // Just take ownership of the inner impl pointer
1647+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, void>();
1648+ _Data._Set_large_fn_ptr(_Old_fn_impl);
1649+ _Func._Set(nullptr);
1650+ }
1651+ }
1652+
15711653 template <class _Vt, class _VtInvQuals, class... _CTypes>
15721654 void _Construct_with_fn(_CTypes&&... _Args) {
1573- _Data._Impl = _Create_impl_ptr<_Vt, _VtInvQuals>();
1655+ _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _VtInvQuals>();
15741656 if constexpr (_Large_function_engaged<_Vt>) {
15751657 _Data._Set_large_fn_ptr(_STD _Function_new_large<_Vt>(_STD forward<_CTypes>(_Args)...));
15761658 } else {
@@ -1661,11 +1743,36 @@ public:
16611743 return _Ret ? _Ret : &_Null_move_only_function;
16621744 }
16631745
1664- template <class _Vt, class _VtInvQuals>
1746+ template <_Impl_kind _Kind, class _Vt, class _VtInvQuals>
16651747 _NODISCARD static constexpr _Impl_t _Create_impl() noexcept {
16661748 _Impl_t _Impl{};
1667- if constexpr (_Large_function_engaged<_Vt>) {
1668- _Impl._Invoke = _Function_inv_large<_Vt, _VtInvQuals, _Rx, _Noexcept, _Types...>;
1749+ if constexpr (_Kind != _Impl_kind::_Usual) {
1750+ _STL_INTERNAL_STATIC_ASSERT(!_Noexcept);
1751+ _STL_INTERNAL_STATIC_ASSERT(is_void_v<_VtInvQuals>);
1752+ using _Fn = remove_pointer_t<decltype(_STD declval<_Vt>()._Getimpl())>;
1753+ if constexpr (_Kind == _Impl_kind::_Old_fn_null) {
1754+ _Impl._Invoke = _Function_old_not_callable<_Rx, _Types...>;
1755+ _Impl._Move = nullptr;
1756+ _Impl._Destroy = nullptr;
1757+ } else if constexpr (_Kind == _Impl_kind::_Old_fn_large) {
1758+ _Impl._Invoke = _Function_inv_old<_Fn, _Function_storage_mode::_Large, _Rx, _Types...>;
1759+ _Impl._Move = nullptr;
1760+ _Impl._Destroy = _Function_destroy_old_large<_Fn>;
1761+ } else {
1762+ #ifdef _WIN64
1763+ static_assert(_Kind == _Impl_kind::_Old_fn_small);
1764+ _Impl._Invoke = _Function_inv_old<_Fn, _Function_storage_mode::_Small, _Rx, _Types...>;
1765+ _Impl._Move = _Function_move_old_small<_Fn>;
1766+ _Impl._Destroy = _Function_destroy_old_small<_Fn>;
1767+ #else // ^^^ 64-bit / 32-bit vvv
1768+ static_assert(_Kind == _Impl_kind::_Old_fn_small_as_large);
1769+ _Impl._Invoke = _Function_inv_old<_Fn, _Function_storage_mode::_Large, _Rx, _Types...>;
1770+ _Impl._Move = nullptr;
1771+ _Impl._Destroy = _Function_destroy_old_small_as_large<_Fn>;
1772+ #endif // ^^^ 32-bit ^^^
1773+ }
1774+ } else if constexpr (_Large_function_engaged<_Vt>) {
1775+ _Impl._Invoke = _Function_inv<_Vt, _VtInvQuals, _Function_storage_mode::_Large, _Rx, _Noexcept, _Types...>;
16691776 _Impl._Move = nullptr;
16701777
16711778 if constexpr (is_trivially_destructible_v<_Vt>) {
@@ -1678,7 +1785,7 @@ public:
16781785 _Impl._Destroy = _Function_destroy_large<_Vt>;
16791786 }
16801787 } else {
1681- _Impl._Invoke = _Function_inv_small <_Vt, _VtInvQuals, _Rx, _Noexcept, _Types...>;
1788+ _Impl._Invoke = _Function_inv <_Vt, _VtInvQuals, _Function_storage_mode::_Small , _Rx, _Noexcept, _Types...>;
16821789
16831790 if constexpr (is_trivially_copyable_v<_Vt> && is_trivially_destructible_v<_Vt>) {
16841791 if constexpr ((_Function_small_copy_size<_Vt>) > _Minimum_function_size) {
@@ -1699,9 +1806,9 @@ public:
16991806 return _Impl;
17001807 }
17011808
1702- template <class _Vt, class _VtInvQuals>
1809+ template <_Impl_kind _Kind, class _Vt, class _VtInvQuals>
17031810 _NODISCARD static const _Impl_t* _Create_impl_ptr() noexcept {
1704- static constexpr _Impl_t _Impl = _Create_impl<_Vt, _VtInvQuals>();
1811+ static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _VtInvQuals>();
17051812 return &_Impl;
17061813 }
17071814};
@@ -1932,16 +2039,20 @@ public:
19322039 using _Vt = decay_t<_Fn>;
19332040 static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. "
19342041 "(N4950 [func.wrap.move.ctor]/6)");
1935-
1936- if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> || _Is_specialization_v<_Vt, move_only_function>) {
1937- if (_Callable == nullptr) {
1938- this->_Reset_to_null();
1939- return;
2042+ if constexpr (is_same_v<_Vt, function<_Signature...>>) {
2043+ this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable));
2044+ } else {
2045+ if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt>
2046+ || _Is_specialization_v<_Vt, move_only_function>) {
2047+ if (_Callable == nullptr) {
2048+ this->_Reset_to_null();
2049+ return;
2050+ }
19402051 }
1941- }
19422052
1943- using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
1944- this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable));
2053+ using _VtInvQuals = _Call::template _VtInvQuals<_Vt>;
2054+ this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable));
2055+ }
19452056 }
19462057
19472058 template <class _Fn, class... _CTypes>
0 commit comments