[libcxx-commits] [libcxx] [libc++] Implement std::move_only_function (P0288R9) (PR #94670)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 6 12:36:50 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>

- [libc++] Add __pointer_int_pair
- [libc++] Implement P0288R9 (move_only_function)


---

Patch is 217.38 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94670.diff


51 Files Affected:

- (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1) 
- (modified) libcxx/docs/ReleaseNotes/19.rst (+1) 
- (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1) 
- (modified) libcxx/include/CMakeLists.txt (+4) 
- (modified) libcxx/include/__configuration/abi.h (+3-1) 
- (added) libcxx/include/__functional/move_only_function.h (+93) 
- (added) libcxx/include/__functional/move_only_function_common.h (+46) 
- (added) libcxx/include/__functional/move_only_function_impl.h (+233) 
- (modified) libcxx/include/__std_clang_module (+1) 
- (added) libcxx/include/__utility/pointer_int_pair.h (+157) 
- (modified) libcxx/include/functional (+1) 
- (modified) libcxx/include/module.modulemap (+4) 
- (modified) libcxx/include/version (+1-1) 
- (modified) libcxx/modules/std.cppm.in (+1) 
- (added) libcxx/test/libcxx/private_headers.verify.cpp (+717) 
- (added) libcxx/test/libcxx/utilities/function.objects/func.wrap/func.wrap.move/assert.engaged.cpp (+20) 
- (added) libcxx/test/libcxx/utilities/pointer_int_pair.pass.cpp (+37) 
- (added) libcxx/test/libcxx/utilities/pointer_int_pair/assert.constructor.pass.cpp (+44) 
- (added) libcxx/test/libcxx/utilities/pointer_int_pair/constinit.verify.cpp (+21) 
- (added) libcxx/test/libcxx/utilities/pointer_int_pair/pointer_int_pair.pass.cpp (+104) 
- (added) libcxx/test/libcxx/utilities/pointer_int_pair/static_asserts.verify.cpp (+23) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp (+10-22) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+10-22) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/functor.pass.cpp (+84) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move.pass.cpp (+91) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move_other.pass.cpp (+62) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/nullptr.pass.cpp (+73) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue.pass.cpp (+102) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const.pass.cpp (+118) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.pass.cpp (+113) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_noexcept.pass.cpp (+102) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal.pass.cpp (+106) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const.pass.cpp (+112) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const_noexcept.pass.cpp (+112) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_noexcept.pass.cpp (+106) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue.pass.cpp (+104) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const.pass.cpp (+107) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const_noexcept.pass.cpp (+107) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_noexcept.pass.cpp (+104) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/common.h (+80) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.pass.cpp (+28) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/functor.pass.cpp (+115) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place.pass.cpp (+46) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place_init_list.pass.cpp (+46) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move.pass.cpp (+106) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move_other.pass.cpp (+44) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.pass.cpp (+28) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.adl.pass.cpp (+73) 
- (added) libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.member.pass.cpp (+73) 
- (modified) libcxx/test/support/type_algorithms.h (+36) 
- (modified) libcxx/utils/generate_feature_test_macro_components.py (-1) 


``````````diff
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 0297068785e8b..69296fdc98ae2 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -340,7 +340,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_mdspan``                                       ``202207L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_move_only_function``                           *unimplemented*
+    ``__cpp_lib_move_only_function``                           ``202110L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_optional``                                     ``202110L``
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst
index 0bc343acd281c..9e142d2bdda92 100644
--- a/libcxx/docs/ReleaseNotes/19.rst
+++ b/libcxx/docs/ReleaseNotes/19.rst
@@ -54,6 +54,7 @@ Implemented Papers
 - P2713R1 - Escaping improvements in ``std::format``
 - P2231R1 - Missing ``constexpr`` in ``std::optional`` and ``std::variant``
 - P0019R8 - ``std::atomic_ref``
+- P0288R9 - ``move_only_function``
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 01387a404f5d6..b5da5cad5f060 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -23,7 +23,7 @@
 "`P2136R3 <https://wg21.link/P2136R3>`__","LWG","invoke_r","June 2021","|Complete|","17.0"
 "`P2166R1 <https://wg21.link/P2166R1>`__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0"
 "","","","","","",""
-"`P0288R9 <https://wg21.link/P0288R9>`__","LWG","``any_invocable``","October 2021","",""
+"`P0288R9 <https://wg21.link/P0288R9>`__","LWG","``move_only_function``","October 2021","|Complete|","19.0"
 "`P0798R8 <https://wg21.link/P0798R8>`__","LWG","Monadic operations for ``std::optional``","October 2021","|Complete|","14.0"
 "`P0849R8 <https://wg21.link/P0849R8>`__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","|Complete|","14.0"
 "`P1072R10 <https://wg21.link/P1072R10>`__","LWG","``basic_string::resize_and_overwrite``","October 2021","|Complete|","14.0"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index cfe1f44777bca..17573d3e67de8 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -399,6 +399,9 @@ set(files
   __functional/is_transparent.h
   __functional/mem_fn.h
   __functional/mem_fun_ref.h
+  __functional/move_only_function.h
+  __functional/move_only_function_common.h
+  __functional/move_only_function_impl.h
   __functional/not_fn.h
   __functional/operations.h
   __functional/perfect_forward.h
@@ -857,6 +860,7 @@ set(files
   __utility/no_destroy.h
   __utility/pair.h
   __utility/piecewise_construct.h
+  __utility/pointer_int_pair.h
   __utility/priority_tag.h
   __utility/private_constructor_tag.h
   __utility/rel_ops.h
diff --git a/libcxx/include/__configuration/abi.h b/libcxx/include/__configuration/abi.h
index 17aceb042f524..31c23ff7fa889 100644
--- a/libcxx/include/__configuration/abi.h
+++ b/libcxx/include/__configuration/abi.h
@@ -90,7 +90,9 @@
 #  define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY
 #  define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW
 // Dont' add an inline namespace for `std::filesystem`
-#    define _LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE
+#  define _LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE
+// Enable clang::trivial_abi for std::move_only_function
+#  define _LIBCPP_ABI_SMALL_BUFFER_TRIVIAL_ABI
 #elif _LIBCPP_ABI_VERSION == 1
 #  if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
 // Enable compiling copies of now inline methods into the dylib to support
diff --git a/libcxx/include/__functional/move_only_function.h b/libcxx/include/__functional/move_only_function.h
new file mode 100644
index 0000000000000..4cda276e37d7f
--- /dev/null
+++ b/libcxx/include/__functional/move_only_function.h
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
+#define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 23
+
+// move_only_function design:
+//
+// move_only_function has a small buffer with a size of `3 * sizeof(void*)` bytes. This buffer can only be used when the
+// object that should be stored is trivially relocatable (currently only when it is trivially move constructible and
+// trivially destructible). There is also a bool in the lower bits of the vptr stored which is set when the contained
+// object is not trivially destructible.
+//
+// trivially relocatable: It would also be possible to store nothrow_move_constructible types, but that would mean
+// that move_only_function itself would not be trivially relocatable anymore. The decision to keep move_only_function
+// trivially relocatable was made because we expect move_only_function to be mostly used to store a functor. To only
+// forward functors there is std::function_ref (not voted in yet, expected in C++26).
+//
+// buffer size: We did a survey of six implementations from various vendors. Three of them had a buffer size of 24 bytes
+// on 64 bit systems. This also allows storing a std::string or std::vector inside the small buffer (once the compiler
+// has full support of trivially_relocatable annotations).
+//
+// trivially-destructible bit: This allows us to keep the overall binary size smaller because we don't have to store
+// a pointer to a noop function inside the vtable. It also avoids loading the vtable during destruction, potentially
+// resulting in fewer cache misses. The downside is that calling the function now also requires setting the lower bits
+// of the pointer to zero, but this is a very fast operation on modern CPUs.
+
+// NOLINTBEGIN(readability-duplicate-include)
+#  define _LIBCPP_IN_MOVE_ONLY_FUNCTION_H
+
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &&
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &&
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &&
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &&
+#  include <__functional/move_only_function_impl.h>
+
+#  undef _LIBCPP_IN_MOVE_ONLY_FUNCTION_H
+// NOLINTEND(readability-duplicate-include)
+
+#endif // _LIBCPP_STD_VER > 20
+
+#endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
diff --git a/libcxx/include/__functional/move_only_function_common.h b/libcxx/include/__functional/move_only_function_common.h
new file mode 100644
index 0000000000000..45978bfc91aad
--- /dev/null
+++ b/libcxx/include/__functional/move_only_function_common.h
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_COMMON_H
+#define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_COMMON_H
+
+#include <__config>
+#include <__type_traits/integral_constant.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class...>
+class move_only_function;
+
+template <class>
+struct __is_move_only_function : false_type {};
+
+template <class... _Args>
+struct __is_move_only_function<move_only_function<_Args...>> : true_type {};
+
+template <class _BufferT, class _ReturnT, class... _ArgTypes>
+struct _MoveOnlyFunctionTrivialVTable {
+  using _CallFunc = _ReturnT(_BufferT&, _ArgTypes...);
+
+  _CallFunc* __call_;
+};
+
+template <class _BufferT, class _ReturnT, class... _ArgTypes>
+struct _MoveOnlyFunctionNonTrivialVTable : _MoveOnlyFunctionTrivialVTable<_BufferT, _ReturnT, _ArgTypes...> {
+  using _DestroyFunc = void(_BufferT&) noexcept;
+
+  _DestroyFunc* __destroy_;
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_COMMON_H
diff --git a/libcxx/include/__functional/move_only_function_impl.h b/libcxx/include/__functional/move_only_function_impl.h
new file mode 100644
index 0000000000000..9d006ea346162
--- /dev/null
+++ b/libcxx/include/__functional/move_only_function_impl.h
@@ -0,0 +1,233 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This header is unguarded on purpose. This header is an implementation detail of move_only_function.h
+// and generates multiple versions of std::move_only_function
+
+#include <__config>
+#include <__functional/invoke.h>
+#include <__functional/move_only_function_common.h>
+#include <__type_traits/is_trivially_destructible.h>
+#include <__utility/exchange.h>
+#include <__utility/forward.h>
+#include <__utility/in_place.h>
+#include <__utility/move.h>
+#include <__utility/pointer_int_pair.h>
+#include <__utility/small_buffer.h>
+#include <__utility/swap.h>
+#include <cstddef>
+#include <cstring>
+#include <initializer_list>
+#include <new>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#ifndef _LIBCPP_IN_MOVE_ONLY_FUNCTION_H
+#  error This header should only be included from move_only_function.h
+#endif
+
+#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_CV
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV
+#endif
+
+#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV&
+#else
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#endif
+
+#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT false
+#endif
+
+#define _LIBCPP_MOVE_ONLY_FUNCTION_CVREF _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#ifdef _LIBCPP_ABI_MOVE_ONLY_FUNCTION_TRIVIAL_ABI
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI [[_Clang::__trivial_abi__]]
+#else
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI
+#endif
+
+template <class...>
+class move_only_function;
+
+template <class _ReturnT, class... _ArgTypes>
+class _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI move_only_function<_ReturnT(
+    _ArgTypes...) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT)> {
+private:
+  static constexpr size_t __buffer_size_      = 3 * sizeof(void*);
+  static constexpr size_t __buffer_alignment_ = alignof(void*);
+  using _BufferT                              = __small_buffer<__buffer_size_, __buffer_alignment_>;
+
+  using _TrivialVTable    = _MoveOnlyFunctionTrivialVTable<_BufferT, _ReturnT, _ArgTypes...>;
+  using _NonTrivialVTable = _MoveOnlyFunctionNonTrivialVTable<_BufferT, _ReturnT, _ArgTypes...>;
+
+  template <class _Functor>
+  static constexpr _TrivialVTable __trivial_vtable_ = {
+      .__call_ = [](_BufferT& __buffer, _ArgTypes... __args) noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) -> _ReturnT {
+        return std::invoke_r<_ReturnT>(
+            static_cast<_Functor _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS>(*__buffer.__get<_Functor>()),
+            std::forward<_ArgTypes>(__args)...);
+      }};
+
+  template <class _Functor>
+  static constexpr _NonTrivialVTable __non_trivial_vtable_{
+      __trivial_vtable_<_Functor>,
+      [](_BufferT& __buffer) noexcept -> void {
+        std::destroy_at(__buffer.__get<_Functor>());
+        __buffer.__dealloc<_Functor>();
+      },
+  };
+
+  template <class _Functor>
+  _LIBCPP_HIDE_FROM_ABI __pointer_bool_pair<const _TrivialVTable*> __get_vptr() {
+    if constexpr (_BufferT::__fits_in_buffer<_Functor> && is_trivially_destructible_v<_Functor>) {
+      return {&__trivial_vtable_<_Functor>, false};
+    } else {
+      return {&__non_trivial_vtable_<_Functor>, true};
+    }
+  }
+
+  template <class _VT>
+  static constexpr bool __is_callable_from = [] {
+    using _DVT = decay_t<_VT>;
+    if (_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) {
+      return is_nothrow_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> &&
+             is_nothrow_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>;
+    } else {
+      return is_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> &&
+             is_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>;
+    }
+  }();
+
+  template <class _Func, class... _Args>
+  _LIBCPP_HIDE_FROM_ABI void __construct(_Args&&... __args) {
+    static_assert(is_constructible_v<decay_t<_Func>, _Func>);
+
+    using _StoredFunc = decay_t<_Func>;
+    __vtable_         = __get_vptr<_StoredFunc>();
+    __buffer_.__construct<_StoredFunc>(std::forward<_Args>(__args)...);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI void __reset() {
+    if (__vtable_.__get_value())
+      static_cast<const _NonTrivialVTable*>(__vtable_.__get_ptr())->__destroy_(__buffer_);
+    __vtable_ = {};
+  }
+
+public:
+  using result_type = _ReturnT;
+
+  // [func.wrap.move.ctor]
+  move_only_function() noexcept = default;
+  _LIBCPP_HIDE_FROM_ABI move_only_function(nullptr_t) noexcept {}
+  _LIBCPP_HIDE_FROM_ABI move_only_function(move_only_function&& __other) noexcept
+      : __vtable_(__other.__vtable_), __buffer_(std::move(__other.__buffer_)) {
+    __other.__vtable_ = {};
+  }
+
+  template <class _Func>
+    requires(!is_same_v<remove_cvref_t<_Func>, move_only_function> && !__is_inplace_type<_Func>::value &&
+             __is_callable_from<_Func>)
+  _LIBCPP_HIDE_FROM_ABI move_only_function(_Func&& __func) noexcept {
+    using _StoredFunc = decay_t<_Func>;
+
+    if constexpr ((is_pointer_v<_StoredFunc> && is_function_v<remove_pointer_t<_StoredFunc>>) ||
+                  is_member_function_pointer_v<_StoredFunc>) {
+      if (__func != nullptr) {
+        __vtable_ = __get_vptr<_StoredFunc>();
+        static_assert(_BufferT::__fits_in_buffer<_StoredFunc>);
+        __buffer_.__construct<_StoredFunc>(std::forward<_Func>(__func));
+      }
+    } else if constexpr (__is_move_only_function<_StoredFunc>::value) {
+      if (__func) {
+        __vtable_ = std::exchange(__func.__vtable_, {});
+        __buffer_ = std::move(__func.__buffer_);
+      }
+    } else {
+      __construct<_Func>(std::forward<_Func>(__func));
+    }
+  }
+
+  template <class _Func, class... _Args>
+    requires is_constructible_v<decay_t<_Func>, _Args...> && __is_callable_from<_Func>
+  _LIBCPP_HIDE_FROM_ABI explicit move_only_function(in_place_type_t<_Func>, _Args&&... __args) {
+    static_assert(is_same_v<decay_t<_Func>, _Func>);
+    __construct<_Func>(std::forward<_Args>(__args)...);
+  }
+
+  template <class _Func, class _InitListType, class... _Args>
+    requires is_constructible_v<decay_t<_Func>, initializer_list<_InitListType>&, _Args...> && __is_callable_from<_Func>
+  _LIBCPP_HIDE_FROM_ABI explicit move_only_function(
+      in_place_type_t<_Func>, initializer_list<_InitListType> __il, _Args&&... __args) {
+    static_assert(is_same_v<decay_t<_Func>, _Func>);
+    __construct<_Func>(__il, std::forward<_Args>(__args)...);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(move_only_function&& __other) noexcept {
+    move_only_function(std::move(__other)).swap(*this);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(nullptr_t) noexcept {
+    __reset();
+    return *this;
+  }
+
+  template <class _Func>
+    requires(!is_same_v<remove_cvref_t<_Func>, move_only_function> && !__is_inplace_type<_Func>::value &&
+             __is_callable_from<_Func>)
+  _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(_Func&& __func) {
+    move_only_function(std::forward<_Func>(__func)).swap(*this);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI ~move_only_function() { __reset(); }
+
+  // [func.wrap.move.inv]
+  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __vtable_.__get_ptr() != nullptr; }
+
+  _LIBCPP_HIDE_FROM_ABI _ReturnT operator()(_ArgTypes... __args) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF
+      noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) {
+    _LIBCPP_ASSERT(static_cast<bool>(*this), "Tried to call a disengaged move_only_function");
+    const auto __call = static_cast<_ReturnT (*)(_BufferT&, _ArgTypes...)>(__vtable_.__get_ptr()->__call_);
+    return __call(__buffer_, std::forward<_ArgTypes>(__args)...);
+  }
+
+  // [func.wrap.move.util]
+  _LIBCPP_HIDE_FROM_ABI void swap(move_only_function& __other) noexcept {
+    std::swap(__vtable_, __other.__vtable_);
+    std::swap(__buffer_, __other.__buffer_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend void swap(move_only_function& __lhs, move_only_function& __rhs) noexcept {
+    __lhs.swap(__rhs);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend bool operator==(const move_only_function& __func, nullptr_t) noexcept { return !__func; }
+
+private:
+  __pointer_bool_pair<const _TrivialVTable*> __vtable_ = {};
+  mutable _BufferT __buffer_;
+
+  template <class...>
+  friend class move_only_function;
+};
+
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_CV
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_CVREF
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module
index 18d6ce6b46c1f..e48a3e876ef84 100644
--- a/libcxx/include/__std_clang_module
+++ b/libcxx/include/__std_clang_module
@@ -136,6 +136,7 @@
 #include <mdspan>
 #include <memory>
 #include <memory_resource>
+#include <module.modulemap.in>
 #include <mutex>
 #include <new>
 #include <numbers>
diff --git a/libcxx/include/__utility/pointer_int_pair.h b/libcxx/include/__utility/pointer_int_pair.h
new file mode 100644
index 0000000000000..5a08b74686166
--- /dev/null
+++ b/libcxx/include/__utility/pointer_int_pair.h
@@ -0,0 +1,157 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Except...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/94670


More information about the libcxx-commits mailing list