Skip to content

Commit b979311

Browse files
authored
[libc++] Remove allocator support from std::function (#140395)
The allocator support was removed in P0302R1, since it was impossible to implement. We're currently providing the API for this, but ignore the allocator in all cases but one (which is almost certainly an oversight). That case is the `function(allocator_arg_t, const Alloc&, Func)` constuctor. IMO we should remove the API entirely at a later date, but this only removes most of the code for now, leaving only the public functions. This not only simplifies the code quite a bit, but also results in the constructor being instantiated ~8x faster. Fixes #133901
1 parent aac603c commit b979311

File tree

2 files changed

+39
-204
lines changed

2 files changed

+39
-204
lines changed

libcxx/docs/ReleaseNotes/21.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ Potentially breaking changes
9999

100100
- User-defined specializations of ``std::common_reference`` are diagnosed now. To customize the common reference type, ``std::basic_common_reference`` should be specialized instead.
101101

102+
- ``std::function`` used to have allocator support, which was removed from the Standard by `http://wg21.link/p0302r1`
103+
due to issues with its design and inconsistent support from implementations. Previously, libc++ would provide
104+
allocator-aware APIs in ``std::function`` in C++11 and C++14, but ignores the allocator argument in all places but
105+
one. Starting in this release, the allocator argument is always ignored.
106+
102107
Announcements About Future Releases
103108
-----------------------------------
104109

libcxx/include/__functional/function.h

Lines changed: 34 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,7 @@
1717
#include <__functional/binary_function.h>
1818
#include <__functional/invoke.h>
1919
#include <__functional/unary_function.h>
20-
#include <__iterator/iterator_traits.h>
2120
#include <__memory/addressof.h>
22-
#include <__memory/allocator.h>
23-
#include <__memory/allocator_destructor.h>
24-
#include <__memory/allocator_traits.h>
25-
#include <__memory/compressed_pair.h>
26-
#include <__memory/unique_ptr.h>
2721
#include <__type_traits/aligned_storage.h>
2822
#include <__type_traits/decay.h>
2923
#include <__type_traits/is_core_convertible.h>
@@ -34,9 +28,7 @@
3428
#include <__type_traits/strip_signature.h>
3529
#include <__utility/forward.h>
3630
#include <__utility/move.h>
37-
#include <__utility/piecewise_construct.h>
3831
#include <__utility/swap.h>
39-
#include <__verbose_abort>
4032
#include <tuple>
4133
#include <typeinfo>
4234

@@ -133,71 +125,9 @@ _LIBCPP_HIDE_FROM_ABI bool __not_null(_Rp (^__p)(_Args...)) {
133125

134126
namespace __function {
135127

136-
// __alloc_func holds a functor and an allocator.
137-
138-
template <class _Fp, class _Ap, class _FB>
139-
class __alloc_func;
140128
template <class _Fp, class _FB>
141129
class __default_alloc_func;
142130

143-
template <class _Fp, class _Ap, class _Rp, class... _ArgTypes>
144-
class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
145-
_LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_);
146-
147-
public:
148-
using _Target _LIBCPP_NODEBUG = _Fp;
149-
using _Alloc _LIBCPP_NODEBUG = _Ap;
150-
151-
_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; }
152-
153-
// WIN32 APIs may define __allocator, so use __get_allocator instead.
154-
_LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __alloc_; }
155-
156-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {}
157-
158-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
159-
160-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a)
161-
: __func_(__f), __alloc_(std::move(__a)) {}
162-
163-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a)
164-
: __func_(std::move(__f)), __alloc_(std::move(__a)) {}
165-
166-
_LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
167-
return std::__invoke_r<_Rp>(__func_, std::forward<_ArgTypes>(__arg)...);
168-
}
169-
170-
_LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const {
171-
typedef allocator_traits<_Alloc> __alloc_traits;
172-
typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA;
173-
_AA __a(__alloc_);
174-
typedef __allocator_destructor<_AA> _Dp;
175-
unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
176-
::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a));
177-
return __hold.release();
178-
}
179-
180-
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT {
181-
__func_.~_Fp();
182-
__alloc_.~_Alloc();
183-
}
184-
185-
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) {
186-
typedef allocator_traits<_Alloc> __alloc_traits;
187-
typedef __rebind_alloc<__alloc_traits, __alloc_func> _FunAlloc;
188-
_FunAlloc __a(__f->__get_allocator());
189-
__f->destroy();
190-
__a.deallocate(__f, 1);
191-
}
192-
};
193-
194-
template <class _Tp>
195-
struct __deallocating_deleter {
196-
_LIBCPP_HIDE_FROM_ABI void operator()(void* __p) const {
197-
std::__libcpp_deallocate<_Tp>(static_cast<_Tp*>(__p), __element_count(1));
198-
}
199-
};
200-
201131
template <class _Fp, class _Rp, class... _ArgTypes>
202132
class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
203133
_Fp __f_;
@@ -215,20 +145,9 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
215145
return std::__invoke_r<_Rp>(__f_, std::forward<_ArgTypes>(__arg)...);
216146
}
217147

218-
_LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const {
219-
using _Self = __default_alloc_func;
220-
unique_ptr<_Self, __deallocating_deleter<_Self>> __hold(std::__libcpp_allocate<_Self>(__element_count(1)));
221-
_Self* __res = ::new ((void*)__hold.get()) _Self(__f_);
222-
(void)__hold.release();
223-
return __res;
224-
}
148+
_LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const { return new __default_alloc_func(__f_); }
225149

226150
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~_Target(); }
227-
228-
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__default_alloc_func* __f) {
229-
__f->destroy();
230-
std::__libcpp_deallocate<__default_alloc_func>(__f, __element_count(1));
231-
}
232151
};
233152

234153
// __base provides an abstract interface for copyable functors.
@@ -257,84 +176,38 @@ class __base<_Rp(_ArgTypes...)> {
257176

258177
// __func implements __base for a given functor type.
259178

260-
template <class _FD, class _Alloc, class _FB>
179+
template <class _FD, class _FB>
261180
class __func;
262181

263-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
264-
class __func<_Fp, _Alloc, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> {
265-
__alloc_func<_Fp, _Alloc, _Rp(_ArgTypes...)> __f_;
182+
template <class _Fp, class _Rp, class... _ArgTypes>
183+
class __func<_Fp, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> {
184+
_Fp __func_;
266185

267186
public:
268-
_LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f) : __f_(std::move(__f)) {}
269-
270-
_LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f, const _Alloc& __a) : __f_(__f, __a) {}
187+
_LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f) : __func_(std::move(__f)) {}
188+
_LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f) : __func_(__f) {}
271189

272-
_LIBCPP_HIDE_FROM_ABI explicit __func(const _Fp& __f, _Alloc&& __a) : __f_(__f, std::move(__a)) {}
190+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL __base<_Rp(_ArgTypes...)>* __clone() const override { return new __func(__func_); }
273191

274-
_LIBCPP_HIDE_FROM_ABI explicit __func(_Fp&& __f, _Alloc&& __a) : __f_(std::move(__f), std::move(__a)) {}
192+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __clone(__base<_Rp(_ArgTypes...)>* __p) const override {
193+
::new ((void*)__p) __func(__func_);
194+
}
275195

276-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __base<_Rp(_ArgTypes...)>* __clone() const;
277-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void __clone(__base<_Rp(_ArgTypes...)>*) const;
278-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy() _NOEXCEPT;
279-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual void destroy_deallocate() _NOEXCEPT;
280-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual _Rp operator()(_ArgTypes&&... __arg);
196+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void destroy() _NOEXCEPT override { __func_.~_Fp(); }
197+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL void destroy_deallocate() _NOEXCEPT override { delete this; }
198+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL _Rp operator()(_ArgTypes&&... __arg) override {
199+
return std::__invoke_r<_Rp>(__func_, std::forward<_ArgTypes>(__arg)...);
200+
}
281201
# if _LIBCPP_HAS_RTTI
282-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const void* target(const type_info&) const _NOEXCEPT;
283-
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual const std::type_info& target_type() const _NOEXCEPT;
202+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL const void* target(const type_info& __ti) const _NOEXCEPT override {
203+
if (__ti == typeid(_Fp))
204+
return std::addressof(__func_);
205+
return nullptr;
206+
}
207+
_LIBCPP_HIDE_FROM_ABI_VIRTUAL const std::type_info& target_type() const _NOEXCEPT override { return typeid(_Fp); }
284208
# endif // _LIBCPP_HAS_RTTI
285209
};
286210

287-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
288-
__base<_Rp(_ArgTypes...)>* __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__clone() const {
289-
typedef allocator_traits<_Alloc> __alloc_traits;
290-
typedef __rebind_alloc<__alloc_traits, __func> _Ap;
291-
_Ap __a(__f_.__get_allocator());
292-
typedef __allocator_destructor<_Ap> _Dp;
293-
unique_ptr<__func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
294-
::new ((void*)__hold.get()) __func(__f_.__target(), _Alloc(__a));
295-
return __hold.release();
296-
}
297-
298-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
299-
void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const {
300-
::new ((void*)__p) __func(__f_.__target(), __f_.__get_allocator());
301-
}
302-
303-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
304-
void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy() _NOEXCEPT {
305-
__f_.destroy();
306-
}
307-
308-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
309-
void __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::destroy_deallocate() _NOEXCEPT {
310-
typedef allocator_traits<_Alloc> __alloc_traits;
311-
typedef __rebind_alloc<__alloc_traits, __func> _Ap;
312-
_Ap __a(__f_.__get_allocator());
313-
__f_.destroy();
314-
__a.deallocate(this, 1);
315-
}
316-
317-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
318-
_Rp __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::operator()(_ArgTypes&&... __arg) {
319-
return __f_(std::forward<_ArgTypes>(__arg)...);
320-
}
321-
322-
# if _LIBCPP_HAS_RTTI
323-
324-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
325-
const void* __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::target(const type_info& __ti) const _NOEXCEPT {
326-
if (__ti == typeid(_Fp))
327-
return std::addressof(__f_.__target());
328-
return nullptr;
329-
}
330-
331-
template <class _Fp, class _Alloc, class _Rp, class... _ArgTypes>
332-
const std::type_info& __func<_Fp, _Alloc, _Rp(_ArgTypes...)>::target_type() const _NOEXCEPT {
333-
return typeid(_Fp);
334-
}
335-
336-
# endif // _LIBCPP_HAS_RTTI
337-
338211
// __value_func creates a value-type from a __func.
339212

340213
template <class _Fp>
@@ -354,29 +227,19 @@ class __value_func<_Rp(_ArgTypes...)> {
354227
public:
355228
_LIBCPP_HIDE_FROM_ABI __value_func() _NOEXCEPT : __f_(nullptr) {}
356229

357-
template <class _Fp, class _Alloc>
358-
_LIBCPP_HIDE_FROM_ABI __value_func(_Fp&& __f, const _Alloc& __a) : __f_(nullptr) {
359-
typedef allocator_traits<_Alloc> __alloc_traits;
360-
typedef __function::__func<_Fp, _Alloc, _Rp(_ArgTypes...)> _Fun;
361-
typedef __rebind_alloc<__alloc_traits, _Fun> _FunAlloc;
230+
template <class _Fp, __enable_if_t<!is_same<__decay_t<_Fp>, __value_func>::value, int> = 0>
231+
_LIBCPP_HIDE_FROM_ABI explicit __value_func(_Fp&& __f) : __f_(nullptr) {
232+
typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _Fun;
362233

363234
if (__function::__not_null(__f)) {
364-
_FunAlloc __af(__a);
365-
if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value &&
366-
is_nothrow_copy_constructible<_FunAlloc>::value) {
367-
__f_ = ::new ((void*)&__buf_) _Fun(std::move(__f), _Alloc(__af));
235+
if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value) {
236+
__f_ = ::new (std::addressof(__buf_)) _Fun(std::move(__f));
368237
} else {
369-
typedef __allocator_destructor<_FunAlloc> _Dp;
370-
unique_ptr<__func, _Dp> __hold(__af.allocate(1), _Dp(__af, 1));
371-
::new ((void*)__hold.get()) _Fun(std::move(__f), _Alloc(__a));
372-
__f_ = __hold.release();
238+
__f_ = new _Fun(std::move(__f));
373239
}
374240
}
375241
}
376242

377-
template <class _Fp, __enable_if_t<!is_same<__decay_t<_Fp>, __value_func>::value, int> = 0>
378-
_LIBCPP_HIDE_FROM_ABI explicit __value_func(_Fp&& __f) : __value_func(std::forward<_Fp>(__f), allocator<_Fp>()) {}
379-
380243
_LIBCPP_HIDE_FROM_ABI __value_func(const __value_func& __f) {
381244
if (__f.__f_ == nullptr)
382245
__f_ = nullptr;
@@ -544,7 +407,7 @@ struct __policy {
544407

545408
template <typename _Fun>
546409
_LIBCPP_HIDE_FROM_ABI static void __large_destroy(void* __s) {
547-
_Fun::__destroy_and_delete(static_cast<_Fun*>(__s));
410+
delete static_cast<_Fun*>(__s);
548411
}
549412

550413
template <typename _Fun>
@@ -583,7 +446,7 @@ struct __policy {
583446
template <typename _Tp>
584447
using __fast_forward _LIBCPP_NODEBUG = __conditional_t<is_scalar<_Tp>::value, _Tp, _Tp&&>;
585448

586-
// __policy_invoker calls an instance of __alloc_func held in __policy_storage.
449+
// __policy_invoker calls an instance of __default_alloc_func held in __policy_storage.
587450

588451
template <class _Fp>
589452
struct __policy_invoker;
@@ -641,28 +504,6 @@ class __policy_func<_Rp(_ArgTypes...)> {
641504
public:
642505
_LIBCPP_HIDE_FROM_ABI __policy_func() : __policy_(__policy::__create_empty()) {}
643506

644-
template <class _Fp, class _Alloc>
645-
_LIBCPP_HIDE_FROM_ABI __policy_func(_Fp&& __f, const _Alloc& __a) : __policy_(__policy::__create_empty()) {
646-
typedef __alloc_func<_Fp, _Alloc, _Rp(_ArgTypes...)> _Fun;
647-
typedef allocator_traits<_Alloc> __alloc_traits;
648-
typedef __rebind_alloc<__alloc_traits, _Fun> _FunAlloc;
649-
650-
if (__function::__not_null(__f)) {
651-
__invoker_ = __invoker::template __create<_Fun>();
652-
__policy_ = __policy::__create<_Fun>();
653-
654-
_FunAlloc __af(__a);
655-
if (__use_small_storage<_Fun>()) {
656-
::new ((void*)&__buf_.__small) _Fun(std::move(__f), _Alloc(__af));
657-
} else {
658-
typedef __allocator_destructor<_FunAlloc> _Dp;
659-
unique_ptr<_Fun, _Dp> __hold(__af.allocate(1), _Dp(__af, 1));
660-
::new ((void*)__hold.get()) _Fun(std::move(__f), _Alloc(__af));
661-
__buf_.__large = __hold.release();
662-
}
663-
}
664-
}
665-
666507
template <class _Fp, __enable_if_t<!is_same<__decay_t<_Fp>, __policy_func>::value, int> = 0>
667508
_LIBCPP_HIDE_FROM_ABI explicit __policy_func(_Fp&& __f) : __policy_(__policy::__create_empty()) {
668509
typedef __default_alloc_func<_Fp, _Rp(_ArgTypes...)> _Fun;
@@ -673,9 +514,7 @@ class __policy_func<_Rp(_ArgTypes...)> {
673514
if (__use_small_storage<_Fun>()) {
674515
::new ((void*)&__buf_.__small) _Fun(std::move(__f));
675516
} else {
676-
unique_ptr<_Fun, __deallocating_deleter<_Fun>> __hold(std::__libcpp_allocate<_Fun>(__element_count(1)));
677-
__buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
678-
(void)__hold.release();
517+
__buf_.__large = ::new _Fun(std::move(__f));
679518
}
680519
}
681520
}
@@ -750,8 +589,8 @@ class __policy_func<_Rp(_ArgTypes...)> {
750589
extern "C" void* _Block_copy(const void*);
751590
extern "C" void _Block_release(const void*);
752591

753-
template <class _Rp1, class... _ArgTypes1, class _Alloc, class _Rp, class... _ArgTypes>
754-
class __func<_Rp1 (^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> {
592+
template <class _Rp1, class... _ArgTypes1, class _Rp, class... _ArgTypes>
593+
class __func<_Rp1 (^)(_ArgTypes1...), _Rp(_ArgTypes...)> : public __base<_Rp(_ArgTypes...)> {
755594
typedef _Rp1 (^__block_type)(_ArgTypes1...);
756595
__block_type __f_;
757596

@@ -767,15 +606,6 @@ class __func<_Rp1 (^)(_ArgTypes1...), _Alloc, _Rp(_ArgTypes...)> : public __base
767606

768607
// [TODO] add && to save on a retain
769608

770-
_LIBCPP_HIDE_FROM_ABI explicit __func(__block_type __f, const _Alloc& /* unused */)
771-
# if __has_feature(objc_arc)
772-
: __f_(__f)
773-
# else
774-
: __f_(reinterpret_cast<__block_type>(__f ? _Block_copy(__f) : nullptr))
775-
# endif
776-
{
777-
}
778-
779609
_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual __base<_Rp(_ArgTypes...)>* __clone() const {
780610
_LIBCPP_ASSERT_INTERNAL(
781611
false,
@@ -954,7 +784,7 @@ function<_Rp(_ArgTypes...)>::function(_Fp __f) : __f_(std::move(__f)) {}
954784
# if _LIBCPP_STD_VER <= 14
955785
template <class _Rp, class... _ArgTypes>
956786
template <class _Fp, class _Alloc, class>
957-
function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc& __a, _Fp __f) : __f_(std::move(__f), __a) {}
787+
function<_Rp(_ArgTypes...)>::function(allocator_arg_t, const _Alloc&, _Fp __f) : __f_(std::move(__f)) {}
958788
# endif
959789

960790
template <class _Rp, class... _ArgTypes>

0 commit comments

Comments
 (0)