Skip to content

Commit a8114cd

Browse files
committed
Do avoid one copying
1 parent c1b8115 commit a8114cd

File tree

1 file changed

+133
-30
lines changed

1 file changed

+133
-30
lines changed

stl/inc/functional

Lines changed: 133 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
10021021
protected:
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

10991111
private:
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

11211122
template <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+
14261433
template <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+
14441463
template <class _Vt>
14451464
void __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+
14611488
template <class _Vt>
14621489
void __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+
14701513
template <size_t _Align>
14711514
void __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

Comments
 (0)