[libcxx-commits] [libcxx] [libc++] Add __simple_tuple and replace a bunch of uses of tuple with it (PR #214566)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 17 05:12:53 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>

`__simply_tuple` is significantly lighter than `tuple`, making it significantly faster to compile. For example, it is 6x faster to compile `std::views::transform(std::identity())` with this. `<mutex>` also becomes ~30% faster to compile.

---

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


27 Files Affected:

- (modified) libcxx/include/CMakeLists.txt (+2-1) 
- (modified) libcxx/include/__functional/bind_back.h (+19-26) 
- (modified) libcxx/include/__functional/bind_front.h (+9-9) 
- (modified) libcxx/include/__functional/perfect_forward.h (+18-15) 
- (modified) libcxx/include/__mutex/once_flag.h (+5-10) 
- (added) libcxx/include/__tuple/simple_tuple.h (+108) 
- (modified) libcxx/include/algorithm (+2) 
- (modified) libcxx/include/future (+7-5) 
- (modified) libcxx/include/module.modulemap.in (+2-1) 
- (modified) libcxx/include/mutex (+8-12) 
- (modified) libcxx/include/numeric (+2) 
- (modified) libcxx/include/tuple (+2-2) 
- (modified) libcxx/include/vector (+4) 
- (modified) libcxx/test/libcxx/transitive_includes/cxx26.csv (-6) 
- (modified) libcxx/test/std/thread/futures/futures.async/async.verify.cpp (+2-4) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/assign.compile.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.guard/copy.compile.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_assign.compile.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/copy_ctor.compile.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/member_swap.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/nonmember_swap.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.mod/release.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/mutex.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp (+1) 
- (modified) libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/owns_lock.pass.cpp (+1) 
- (modified) libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp (+2-2) 
- (modified) libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp (+1-1) 


``````````diff
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d24ae7a73a825..21276786837c3 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -619,7 +619,7 @@ set(files
   __memory/noexcept_move_assign_container.h
   __memory/out_ptr.h
   __memory/pointer_traits.h
-  __memory/pstl.h  
+  __memory/pstl.h
   __memory/ranges_construct_at.h
   __memory/ranges_destroy.h
   __memory/ranges_uninitialized_algorithms.h
@@ -830,6 +830,7 @@ set(files
   __tuple/find_index.h
   __tuple/ignore.h
   __tuple/sfinae_helpers.h
+  __tuple/simple_tuple.h
   __tuple/tuple_element.h
   __tuple/tuple_like.h
   __tuple/tuple_like_no_subrange.h
diff --git a/libcxx/include/__functional/bind_back.h b/libcxx/include/__functional/bind_back.h
index 41177144d81fe..575d7813f7d59 100644
--- a/libcxx/include/__functional/bind_back.h
+++ b/libcxx/include/__functional/bind_back.h
@@ -13,10 +13,10 @@
 #include <__config>
 #include <__functional/invoke.h>
 #include <__functional/perfect_forward.h>
+#include <__tuple/simple_tuple.h>
 #include <__type_traits/decay.h>
 #include <__utility/forward.h>
 #include <__utility/integer_sequence.h>
-#include <tuple>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -26,40 +26,33 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 20
 
-template <size_t _NBound, class = make_index_sequence<_NBound>>
-struct __bind_back_op;
-
-template <size_t _NBound, size_t... _Ip>
-struct __bind_back_op<_NBound, index_sequence<_Ip...>> {
+struct __bind_back_op {
   template <class _Fn, class _BoundArgs, class... _Args>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __f, _BoundArgs&& __bound_args, _Args&&... __args) const
-      noexcept(noexcept(std::invoke(std::forward<_Fn>(__f),
-                                    std::forward<_Args>(__args)...,
-                                    std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...)))
-          -> decltype(std::invoke(std::forward<_Fn>(__f),
-                                  std::forward<_Args>(__args)...,
-                                  std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...)) {
-    return std::invoke(std::forward<_Fn>(__f),
-                       std::forward<_Args>(__args)...,
-                       std::get<_Ip>(std::forward<_BoundArgs>(__bound_args))...);
+      noexcept(noexcept(decay_t<_BoundArgs>::__apply_back(
+          std::forward<_BoundArgs>(__bound_args), std::forward<_Fn>(__f), std::forward<_Args>(__args)...)))
+          -> decltype(decay_t<_BoundArgs>::__apply_back(
+              std::forward<_BoundArgs>(__bound_args), std::forward<_Fn>(__f), std::forward<_Args>(__args)...)) {
+    return decay_t<_BoundArgs>::__apply_back(
+        std::forward<_BoundArgs>(__bound_args), std::forward<_Fn>(__f), std::forward<_Args>(__args)...);
   }
 };
 
 template <class _Fn, class _BoundArgs>
-struct __bind_back_t : __perfect_forward<__bind_back_op<tuple_size_v<_BoundArgs>>, _Fn, _BoundArgs> {
-  using __perfect_forward<__bind_back_op<tuple_size_v<_BoundArgs>>, _Fn, _BoundArgs>::__perfect_forward;
+struct __bind_back_t : __perfect_forward<__bind_back_op, _Fn, _BoundArgs> {
+  using __perfect_forward<__bind_back_op, _Fn, _BoundArgs>::__perfect_forward;
 };
 
 template <class _Fn, class... _Args>
   requires is_constructible_v<decay_t<_Fn>, _Fn> && is_move_constructible_v<decay_t<_Fn>> &&
-               (is_constructible_v<decay_t<_Args>, _Args> && ...) && (is_move_constructible_v<decay_t<_Args>> && ...)
+           (is_constructible_v<decay_t<_Args>, _Args> && ...) && (is_move_constructible_v<decay_t<_Args>> && ...)
 _LIBCPP_HIDE_FROM_ABI constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) noexcept(
-    noexcept(__bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-        std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))))
-    -> decltype(__bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-        std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))) {
-  return __bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-      std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...));
+    noexcept(__bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+        std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...))))
+    -> decltype(__bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+        std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...))) {
+  return __bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+      std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...));
 }
 
 #  if _LIBCPP_STD_VER >= 23
@@ -71,8 +64,8 @@ template <class _Fn, class... _Args>
                 "bind_back requires all decay_t<Args> to be constructible from respective Args");
   static_assert((is_move_constructible_v<decay_t<_Args>> && ...),
                 "bind_back requires all decay_t<Args> to be move constructible");
-  return __bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
-      std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...));
+  return __bind_back_t<decay_t<_Fn>, __simple_tuple<decay_t<_Args>...>>(
+      std::forward<_Fn>(__f), __simple_tuple<decay_t<_Args>...>(std::forward<_Args>(__args)...));
 }
 #  endif // _LIBCPP_STD_VER >= 23
 
diff --git a/libcxx/include/__functional/bind_front.h b/libcxx/include/__functional/bind_front.h
index 97f8f4c458702..de354bbdb0f4a 100644
--- a/libcxx/include/__functional/bind_front.h
+++ b/libcxx/include/__functional/bind_front.h
@@ -31,8 +31,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 struct __bind_front_op {
   template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const noexcept(
-      noexcept(std::invoke(std::forward<_Args>(__args)...))) -> decltype(std::invoke(std::forward<_Args>(__args)...)) {
+  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const
+      noexcept(noexcept(std::invoke(std::forward<_Args>(__args)...)))
+          -> decltype(std::invoke(std::forward<_Args>(__args)...)) {
     return std::invoke(std::forward<_Args>(__args)...);
   }
 };
@@ -58,15 +59,14 @@ struct __nttp_bind_front_t;
 
 template <auto _Fn, size_t... _Indices, class... _BoundArgs>
 struct __nttp_bind_front_t<_Fn, index_sequence<_Indices...>, _BoundArgs...> {
-  tuple<_BoundArgs...> __bound_args_;
+  using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_BoundArgs...>;
+  _TupleT __bound_args_;
 
   template <class _Self, class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(this _Self&& __self, _Args&&... __args) noexcept(noexcept(std::invoke(
-      _Fn, std::get<_Indices>(std::forward<_Self>(__self).__bound_args_)..., std::forward<_Args>(__args)...)))
-      -> decltype(std::invoke(
-          _Fn, std::get<_Indices>(std::forward<_Self>(__self).__bound_args_)..., std::forward<_Args>(__args)...)) {
-    return std::invoke(
-        _Fn, std::get<_Indices>(std::forward<_Self>(__self).__bound_args_)..., std::forward<_Args>(__args)...);
+  _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(this _Self&& __self, _Args&&... __args) noexcept(
+      noexcept(_TupleT::__apply(std::forward<_Self>(__self).__bound_args_, _Fn, std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(std::forward<_Self>(__self).__bound_args_, _Fn, std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(std::forward<_Self>(__self).__bound_args_, _Fn, std::forward<_Args>(__args)...);
   }
 };
 
diff --git a/libcxx/include/__functional/perfect_forward.h b/libcxx/include/__functional/perfect_forward.h
index c0408b410e2f9..83ef1c3ba1331 100644
--- a/libcxx/include/__functional/perfect_forward.h
+++ b/libcxx/include/__functional/perfect_forward.h
@@ -12,6 +12,8 @@
 
 #include <__config>
 #include <__cstddef/size_t.h>
+#include <__tuple/simple_tuple.h>
+#include <__type_traits/conjunction.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_constructible.h>
@@ -19,7 +21,6 @@
 #include <__utility/forward.h>
 #include <__utility/integer_sequence.h>
 #include <__utility/move.h>
-#include <tuple>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -38,10 +39,12 @@ struct __perfect_forward_impl;
 template <class _Op, size_t... _Idx, class... _BoundArgs>
 struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 private:
-  tuple<_BoundArgs...> __bound_args_;
+  using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_BoundArgs...>;
+
+  _TupleT __bound_args_;
 
 public:
-  template <class... _Args, class = enable_if_t< is_constructible_v<tuple<_BoundArgs...>, _Args&&...> >>
+  template <class... _Args, enable_if_t<_And<is_constructible<_BoundArgs, _Args&&>...>::value, int> = 0>
   _LIBCPP_HIDE_FROM_ABI explicit constexpr __perfect_forward_impl(_Args&&... __bound_args)
       : __bound_args_(std::forward<_Args>(__bound_args)...) {}
 
@@ -53,9 +56,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs&..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) & noexcept(
-      noexcept(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs&..., _Args...>>>
@@ -63,9 +66,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs const&..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const& noexcept(
-      noexcept(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(__bound_args_)..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(__bound_args_, _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs const&..., _Args...>>>
@@ -73,9 +76,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) && noexcept(
-      noexcept(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs..., _Args...>>>
@@ -83,9 +86,9 @@ struct __perfect_forward_impl<_Op, index_sequence<_Idx...>, _BoundArgs...> {
 
   template <class... _Args, class = enable_if_t<is_invocable_v<_Op, _BoundArgs const..., _Args...>>>
   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Args&&... __args) const&& noexcept(
-      noexcept(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)))
-      -> decltype(_Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...)) {
-    return _Op()(std::get<_Idx>(std::move(__bound_args_))..., std::forward<_Args>(__args)...);
+      noexcept(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)))
+      -> decltype(_TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...)) {
+    return _TupleT::__apply(std::move(__bound_args_), _Op(), std::forward<_Args>(__args)...);
   }
 
   template <class... _Args, class = enable_if_t<!is_invocable_v<_Op, _BoundArgs const..., _Args...>>>
diff --git a/libcxx/include/__mutex/once_flag.h b/libcxx/include/__mutex/once_flag.h
index 9999852b8b78a..f5cc8bed2d19a 100644
--- a/libcxx/include/__mutex/once_flag.h
+++ b/libcxx/include/__mutex/once_flag.h
@@ -11,15 +11,10 @@
 
 #include <__config>
 #include <__memory/addressof.h>
-#include <__tuple/tuple_size.h>
+#include <__tuple/simple_tuple.h>
 #include <__type_traits/invoke.h>
 #include <__utility/forward.h>
-#include <__utility/integer_sequence.h>
 #include <__utility/move.h>
-#include <cstdint>
-#ifndef _LIBCPP_CXX03_LANG
-#  include <tuple>
-#endif
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -87,9 +82,9 @@ class __call_once_param {
   _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {}
 
   _LIBCPP_HIDE_FROM_ABI void operator()() {
-    [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> void {
-      std::__invoke(std::get<_Indices>(std::move(__f_))...);
-    }(__make_index_sequence<tuple_size<_Fp>::value>());
+    _Fp::__apply(std::move(__f_), []<class... _Args>(_Args&&... __args) -> void {
+      std::__invoke(std::forward<_Args>(__args)...);
+    });
   }
 };
 
@@ -131,7 +126,7 @@ inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_acquire_load(_ValueType const*
 template <class _Callable, class... _Args>
 inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) {
   if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) {
-    typedef tuple<_Callable&&, _Args&&...> _Gp;
+    typedef __simple_tuple<_Callable&&, _Args&&...> _Gp;
     _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...);
     __call_once_param<_Gp> __p(__f);
     std::__call_once(__flag.__state_, std::addressof(__p), std::addressof(__call_once_proxy<_Gp>));
diff --git a/libcxx/include/__tuple/simple_tuple.h b/libcxx/include/__tuple/simple_tuple.h
new file mode 100644
index 0000000000000..71da2f19679a6
--- /dev/null
+++ b/libcxx/include/__tuple/simple_tuple.h
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___TUPLE_SIMPLE_TUPLE_H
+#define _LIBCPP___TUPLE_SIMPLE_TUPLE_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/copy_cvref.h>
+#include <__type_traits/disjunction.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_empty.h>
+#include <__type_traits/is_final.h>
+#include <__type_traits/is_reference.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/remove_cvref.h>
+#include <__utility/forward.h>
+#include <__utility/integer_sequence.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#ifndef _LIBCPP_CXX03_LANG
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <size_t, class _Tp, bool = is_empty<_Tp>::value && !__is_final_v<_Tp>>
+struct __simple_tuple_base {
+  _Tp __val_;
+
+  __simple_tuple_base() = default;
+
+  template <class _Arg, __enable_if_t<_IsNotSame<__remove_cvref_t<_Arg>, __simple_tuple_base>::value, int> = 0>
+  constexpr __simple_tuple_base(_Arg&& __arg) : __val_(std::forward<_Arg>(__arg)) {}
+};
+
+template <size_t _Index, class _Tp>
+struct __simple_tuple_base<_Index, _Tp, true> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_;
+
+  __simple_tuple_base() = default;
+
+  template <class _Arg, __enable_if_t<_IsNotSame<__remove_cvref_t<_Arg>, __simple_tuple_base>::value, int> = 0>
+  constexpr __simple_tuple_base(_Arg&& __arg) : __val_(std::forward<_Arg>(__arg)) {}
+};
+
+template <class _IndexSequence, class... _Bases>
+struct __simple_tuple_impl;
+
+template <class _Ap, class _Bp>
+using __tuple_forward _LIBCPP_NODEBUG = _If<is_reference<_Bp>::value, _Bp, __copy_cvref_t<_Ap, _Bp>>;
+
+template <size_t... _Indices, class... _Types>
+struct __simple_tuple_impl<__index_sequence<_Indices...>, _Types...> : __simple_tuple_base<_Indices, _Types>... {
+  __simple_tuple_impl() = default;
+
+  template <class... _Args,
+            __enable_if_t<_Or<integral_constant<bool, (sizeof...(_Args) != 1)>,
+                              _IsNotSame<__remove_cvref_t<_Args>, __simple_tuple_impl>...>::value,
+                          int> = 0>
+  constexpr __simple_tuple_impl(_Args&&... __args)
+      : __simple_tuple_base<_Indices, _Types>(std::forward<_Args>(__args))... {}
+
+  template <class _Self, class _Func, class... _Args>
+  static constexpr auto __apply(_Self&& __self, _Func&& __func, _Args&&... __args) noexcept(
+      __is_nothrow_invocable_v<_Func, __tuple_forward<_Self, _Types>..., _Args...>)
+      -> __invoke_result_t<_Func, __tuple_forward<_Self, _Types>..., _Args...> {
+    return std::__invoke(
+        std::forward<_Func>(__func),
+        static_cast<__tuple_forward<_Self, _Types>&&>(
+            static_cast<__copy_cvref_t<_Self, __simple_tuple_base<_Indices, _Types>>&&>(__self).__val_)...,
+        std::forward<_Args>(__args)...);
+  }
+
+  template <class _Self, class _Func, class... _Args>
+  static constexpr auto __apply_back(_Self&& __self, _Func&& __func, _Args&&... __args) noexcept(
+      __is_nothrow_invocable_v<_Func, _Args..., __tuple_forward<_Self, _Types>...>)
+      -> __invoke_result_t<_Func, _Args..., __tuple_forward<_Self, _Types>...> {
+    return std::__invoke(
+        std::forward<_Func>(__func),
+        std::forward<_Args>(__args)...,
+        static_cast<__tuple_forward<_Self, _Types>&&>(
+            static_cast<__copy_cvref_t<_Self, __simple_tuple_base<_Indices, _Types>>&&>(__self).__val_)...);
+  }
+};
+
+template <class... _Args>
+using __simple_tuple _LIBCPP_NODEBUG = __simple_tuple_impl<__index_sequence_for<_Args...>, _Args...>;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_CXX03_LANG
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___TUPLE_SIMPLE_TUPLE_H
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 1e1587cc56131..63eae0aa37b4a 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -2106,7 +2106,9 @@ template <class BidirectionalIterator, class Compare>
 
 #  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER >= 17 && _LIBCPP_STD_VER <= 23
 #    include <optional>
+#    include <tuple>
 #  endif
+
 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 
 #endif // _LIBCPP_ALGORITHM
diff --git a/libcxx/include/future b/libcxx/include/future
index 30091660a4286..fa331887299df 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -390,9 +390,11 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
 #    include <__system_error/error_code.h>
 #    include <__system_error/error_condition.h>
 #    include <__thread/thread.h>
+#    include <__tuple/simple_tuple.h>
 #    include <__type_traits/add_reference.h>
 #    include <__type_traits/aligned_storage.h>
 #    include <__type_traits/conditional.h>
+#    include <__type_traits/conjunction.h>
 #    include <__type_traits/decay.h>
 #    include <__type_traits/enable_if.h>
 #    include <__type_traits/invoke.h>
@@ -408,7 +410,6 @@ template <class R, class Alloc> struct uses_allocator<packag...
[truncated]

``````````

</details>


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


More information about the libcxx-commits mailing list