Skip to content

[libc++] Simplify std::function further after removing allocator support #144443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 21, 2025

Conversation

philnik777
Copy link
Contributor

@philnik777 philnik777 commented Jun 16, 2025

Since we've removed allocator support, we can remove a few support structures. This only affects the policy implementation, so this shouldn't even be ABI sensitive.

Copy link

github-actions bot commented Jun 16, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h -- libcxx/include/__functional/function.h
View the diff from clang-format here.
diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index f0c00c56c..dc112ebfd 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -456,7 +456,7 @@ public:
   template <class _Fp, __enable_if_t<!is_same<__decay_t<_Fp>, __policy_func>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI explicit __policy_func(_Fp&& __f) : __policy_(__policy::__create_empty()) {
     if (__function::__not_null(__f)) {
-      __func_ = __call_func<_Fp>;
+      __func_   = __call_func<_Fp>;
       __policy_ = __policy::__create<_Fp>();
       if (__use_small_storage<_Fp>()) {
         ::new ((void*)&__buf_.__small) _Fp(std::move(__f));

@philnik777 philnik777 marked this pull request as ready for review June 19, 2025 08:02
@philnik777 philnik777 requested a review from a team as a code owner June 19, 2025 08:02
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jun 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 19, 2025

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

Since we've removed allocator support, we can remove a few support structures. This only affects the policy implementation, so this shouldn't even be ABI sensitive.


Full diff: https://github.com/llvm/llvm-project/pull/144443.diff

1 Files Affected:

  • (modified) libcxx/include/__functional/function.h (+37-90)
diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index e71c778386fd2..f0c00c56c1466 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -125,31 +125,6 @@ _LIBCPP_HIDE_FROM_ABI bool __not_null(_Rp (^__p)(_Args...)) {
 
 namespace __function {
 
-template <class _Fp, class _FB>
-class __default_alloc_func;
-
-template <class _Fp, class _Rp, class... _ArgTypes>
-class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
-  _Fp __f_;
-
-public:
-  using _Target _LIBCPP_NODEBUG = _Fp;
-
-  _LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_; }
-
-  _LIBCPP_HIDE_FROM_ABI explicit __default_alloc_func(_Target&& __f) : __f_(std::move(__f)) {}
-
-  _LIBCPP_HIDE_FROM_ABI explicit __default_alloc_func(const _Target& __f) : __f_(__f) {}
-
-  _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
-    return std::__invoke_r<_Rp>(__f_, std::forward<_ArgTypes>(__arg)...);
-  }
-
-  _LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const { return new __default_alloc_func(__f_); }
-
-  _LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~_Target(); }
-};
-
 // __base provides an abstract interface for copyable functors.
 
 template <class _Fp>
@@ -402,7 +377,7 @@ struct __policy {
   template <typename _Fun>
   _LIBCPP_HIDE_FROM_ABI static void* __large_clone(const void* __s) {
     const _Fun* __f = static_cast<const _Fun*>(__s);
-    return __f->__clone();
+    return new _Fun(*__f);
   }
 
   template <typename _Fun>
@@ -417,7 +392,7 @@ struct __policy {
         std::addressof(__large_destroy<_Fun>),
         false,
 #  if _LIBCPP_HAS_RTTI
-        &typeid(typename _Fun::_Target)
+        &typeid(_Fun)
 #  else
         nullptr
 #  endif
@@ -432,7 +407,7 @@ struct __policy {
         nullptr,
         false,
 #  if _LIBCPP_HAS_RTTI
-        &typeid(typename _Fun::_Target)
+        &typeid(_Fun)
 #  else
         nullptr
 #  endif
@@ -446,42 +421,7 @@ struct __policy {
 template <typename _Tp>
 using __fast_forward _LIBCPP_NODEBUG = __conditional_t<is_scalar<_Tp>::value, _Tp, _Tp&&>;
 
-// __policy_invoker calls an instance of __default_alloc_func held in __policy_storage.
-
-template <class _Fp>
-struct __policy_invoker;
-
-template <class _Rp, class... _ArgTypes>
-struct __policy_invoker<_Rp(_ArgTypes...)> {
-  typedef _Rp (*__Call)(const __policy_storage*, __fast_forward<_ArgTypes>...);
-
-  __Call __call_;
-
-  // Creates an invoker that throws bad_function_call.
-  _LIBCPP_HIDE_FROM_ABI __policy_invoker() : __call_(&__call_empty) {}
-
-  // Creates an invoker that calls the given instance of __func.
-  template <typename _Fun>
-  _LIBCPP_HIDE_FROM_ABI static __policy_invoker __create() {
-    return __policy_invoker(std::addressof(__call_impl<_Fun>));
-  }
-
-private:
-  _LIBCPP_HIDE_FROM_ABI explicit __policy_invoker(__Call __c) : __call_(__c) {}
-
-  _LIBCPP_HIDE_FROM_ABI static _Rp __call_empty(const __policy_storage*, __fast_forward<_ArgTypes>...) {
-    std::__throw_bad_function_call();
-  }
-
-  template <typename _Fun>
-  _LIBCPP_HIDE_FROM_ABI static _Rp __call_impl(const __policy_storage* __buf, __fast_forward<_ArgTypes>... __args) {
-    _Fun* __f = reinterpret_cast<_Fun*>(__use_small_storage<_Fun>::value ? &__buf->__small : __buf->__large);
-    return (*__f)(std::forward<_ArgTypes>(__args)...);
-  }
-};
-
-// __policy_func uses a __policy and __policy_invoker to create a type-erased,
-// copyable functor.
+// __policy_func uses a __policy to create a type-erased, copyable functor.
 
 template <class _Fp>
 class __policy_func;
@@ -491,45 +431,52 @@ class __policy_func<_Rp(_ArgTypes...)> {
   // Inline storage for small objects.
   __policy_storage __buf_;
 
-  // Calls the value stored in __buf_. This could technically be part of
-  // policy, but storing it here eliminates a level of indirection inside
-  // operator().
-  typedef __function::__policy_invoker<_Rp(_ArgTypes...)> __invoker;
-  __invoker __invoker_;
+  using _ErasedFunc _LIBCPP_NODEBUG = _Rp(const __policy_storage*, __fast_forward<_ArgTypes>...);
+
+  _ErasedFunc* __func_;
 
   // The policy that describes how to move / copy / destroy __buf_. Never
   // null, even if the function is empty.
   const __policy* __policy_;
 
+  _LIBCPP_HIDE_FROM_ABI static _Rp __empty_func(const __policy_storage*, __fast_forward<_ArgTypes>...) {
+    std::__throw_bad_function_call();
+  }
+
+  template <class _Fun>
+  _LIBCPP_HIDE_FROM_ABI static _Rp __call_func(const __policy_storage* __buf, __fast_forward<_ArgTypes>... __args) {
+    _Fun* __func = reinterpret_cast<_Fun*>(__use_small_storage<_Fun>::value ? &__buf->__small : __buf->__large);
+
+    return std::__invoke_r<_Rp>(*__func, std::forward<_ArgTypes>(__args)...);
+  }
+
 public:
-  _LIBCPP_HIDE_FROM_ABI __policy_func() : __policy_(__policy::__create_empty()) {}
+  _LIBCPP_HIDE_FROM_ABI __policy_func() : __func_(__empty_func), __policy_(__policy::__create_empty()) {}
 
   template <class _Fp, __enable_if_t<!is_same<__decay_t<_Fp>, __policy_func>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI explicit __policy_func(_Fp&& __f) : __policy_(__policy::__create_empty()) {
-    typedef __default_alloc_func<_Fp, _Rp(_ArgTypes...)> _Fun;
-
     if (__function::__not_null(__f)) {
-      __invoker_ = __invoker::template __create<_Fun>();
-      __policy_  = __policy::__create<_Fun>();
-      if (__use_small_storage<_Fun>()) {
-        ::new ((void*)&__buf_.__small) _Fun(std::move(__f));
+      __func_ = __call_func<_Fp>;
+      __policy_ = __policy::__create<_Fp>();
+      if (__use_small_storage<_Fp>()) {
+        ::new ((void*)&__buf_.__small) _Fp(std::move(__f));
       } else {
-        __buf_.__large = ::new _Fun(std::move(__f));
+        __buf_.__large = ::new _Fp(std::move(__f));
       }
     }
   }
 
   _LIBCPP_HIDE_FROM_ABI __policy_func(const __policy_func& __f)
-      : __buf_(__f.__buf_), __invoker_(__f.__invoker_), __policy_(__f.__policy_) {
+      : __buf_(__f.__buf_), __func_(__f.__func_), __policy_(__f.__policy_) {
     if (__policy_->__clone)
       __buf_.__large = __policy_->__clone(__f.__buf_.__large);
   }
 
   _LIBCPP_HIDE_FROM_ABI __policy_func(__policy_func&& __f)
-      : __buf_(__f.__buf_), __invoker_(__f.__invoker_), __policy_(__f.__policy_) {
+      : __buf_(__f.__buf_), __func_(__f.__func_), __policy_(__f.__policy_) {
     if (__policy_->__destroy) {
-      __f.__policy_  = __policy::__create_empty();
-      __f.__invoker_ = __invoker();
+      __f.__policy_ = __policy::__create_empty();
+      __f.__func_   = {};
     }
   }
 
@@ -539,30 +486,30 @@ class __policy_func<_Rp(_ArgTypes...)> {
   }
 
   _LIBCPP_HIDE_FROM_ABI __policy_func& operator=(__policy_func&& __f) {
-    *this          = nullptr;
-    __buf_         = __f.__buf_;
-    __invoker_     = __f.__invoker_;
-    __policy_      = __f.__policy_;
-    __f.__policy_  = __policy::__create_empty();
-    __f.__invoker_ = __invoker();
+    *this         = nullptr;
+    __buf_        = __f.__buf_;
+    __func_       = __f.__func_;
+    __policy_     = __f.__policy_;
+    __f.__policy_ = __policy::__create_empty();
+    __f.__func_   = {};
     return *this;
   }
 
   _LIBCPP_HIDE_FROM_ABI __policy_func& operator=(nullptr_t) {
     const __policy* __p = __policy_;
     __policy_           = __policy::__create_empty();
-    __invoker_          = __invoker();
+    __func_             = {};
     if (__p->__destroy)
       __p->__destroy(__buf_.__large);
     return *this;
   }
 
   _LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __args) const {
-    return __invoker_.__call_(std::addressof(__buf_), std::forward<_ArgTypes>(__args)...);
+    return __func_(std::addressof(__buf_), std::forward<_ArgTypes>(__args)...);
   }
 
   _LIBCPP_HIDE_FROM_ABI void swap(__policy_func& __f) {
-    std::swap(__invoker_, __f.__invoker_);
+    std::swap(__func_, __f.__func_);
     std::swap(__policy_, __f.__policy_);
     std::swap(__buf_, __f.__buf_);
   }

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but the clang-format issue seems legitimate. Please fix it before landing!

@philnik777 philnik777 merged commit 2050d2e into llvm:main Jun 21, 2025
11 of 13 checks passed
@philnik777 philnik777 deleted the simplify_function branch June 21, 2025 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy