[libcxx-commits] [libcxx] [libc++] Add __simple_tuple and replace a bunch of uses of tuple with it (PR #214566)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Aug 12 03:37:34 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/214566
>From f93f39d35d20b203b021c930f437fcb6c8f97d04 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 6 Aug 2026 21:55:00 +0200
Subject: [PATCH] [libc++] Add __simple_tuple and replace a bunch of uses of
tuple with it
---
libcxx/include/CMakeLists.txt | 3 +-
libcxx/include/__functional/bind_back.h | 45 +++-----
libcxx/include/__functional/bind_front.h | 18 +--
libcxx/include/__functional/perfect_forward.h | 33 +++---
libcxx/include/__mutex/once_flag.h | 15 +--
libcxx/include/__tuple/simple_tuple.h | 108 ++++++++++++++++++
libcxx/include/algorithm | 2 +
libcxx/include/future | 10 +-
libcxx/include/module.modulemap.in | 3 +-
libcxx/include/mutex | 20 ++--
libcxx/include/numeric | 2 +
libcxx/include/tuple | 4 +-
libcxx/include/vector | 4 +
.../test/libcxx/transitive_includes/cxx26.csv | 6 -
.../futures/futures.async/async.verify.cpp | 6 +-
.../func.bind.partial/bind_back.verify.cpp | 4 +-
.../bind_front.nttp.verify.cpp | 2 +-
17 files changed, 191 insertions(+), 94 deletions(-)
create mode 100644 libcxx/include/__tuple/simple_tuple.h
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..058b8858ba98e 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) {
+ 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..44ec47ccd5c15
--- /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..a37f79ba9cf8e 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<packaged_task<R>, Alloc>;
# include <__utility/move.h>
# include <__utility/swap.h>
# include <stdexcept>
-# include <tuple>
# include <version>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -1831,7 +1832,8 @@ _LIBCPP_HIDE_FROM_ABI future<_Rp> __make_async_assoc_state(_Fp&& __f) {
template <class _Fp, class... _Args>
class _LIBCPP_HIDDEN __async_func {
- tuple<_Fp, _Args...> __f_;
+ using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_Fp, _Args...>;
+ _TupleT __f_;
public:
using _Rp _LIBCPP_NODEBUG = __invoke_result_t<_Fp, _Args...>;
@@ -1843,9 +1845,7 @@ public:
_LIBCPP_HIDE_FROM_ABI __async_func(__async_func&& __f) : __f_(std::move(__f.__f_)) {}
_LIBCPP_HIDE_FROM_ABI _Rp operator()() {
- return [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> _Rp {
- return std::__invoke(std::move(std::get<_Indices>(__f_))...);
- }(__index_sequence_for<_Fp, _Args...>{});
+ return _TupleT::__apply(__f_, [](auto&&... __args) -> _Rp { return std::__invoke(std::move(__args)...); });
}
};
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index a5eac9fc149f0..036ffd4b5f32d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1701,7 +1701,7 @@ module std {
module noexcept_move_assign_container { header "__memory/noexcept_move_assign_container.h" }
module out_ptr { header "__memory/out_ptr.h" }
module pointer_traits { header "__memory/pointer_traits.h" }
- module pstl { header "__memory/pstl.h" }
+ module pstl { header "__memory/pstl.h" }
module ranges_construct_at { header "__memory/ranges_construct_at.h" }
module ranges_destroy { header "__memory/ranges_destroy.h" }
module ranges_uninitialized_algorithms {
@@ -2212,6 +2212,7 @@ module std {
module find_index { header "__tuple/find_index.h" }
module ignore { header "__tuple/ignore.h" }
module sfinae_helpers { header "__tuple/sfinae_helpers.h" }
+ module simple_tuple { header "__tuple/simple_tuple.h" }
module tuple_element { header "__tuple/tuple_element.h" }
module tuple_like_no_subrange { header "__tuple/tuple_like_no_subrange.h" }
module tuple_like { header "__tuple/tuple_like.h" }
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 24e6cab850c46..dc06b23ce1bda 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -200,11 +200,9 @@ template<class Callable, class ...Args>
# include <__mutex/unique_lock.h>
# include <__thread/id.h>
# include <__thread/support.h>
+# include <__tuple/simple_tuple.h>
# include <__utility/forward.h>
# include <limits>
-# ifndef _LIBCPP_CXX03_LANG
-# include <tuple>
-# endif
# include <version>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -471,7 +469,7 @@ public:
template <class... _MArgs>
class _LIBCPP_SCOPED_LOCKABLE scoped_lock {
static_assert(sizeof...(_MArgs) > 1, "At least 2 lock types required");
- typedef tuple<_MArgs&...> _MutexTuple;
+ using _TupleT _LIBCPP_NODEBUG = __simple_tuple<_MArgs&...>;
public:
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit scoped_lock(_MArgs&... __margs) _LIBCPP_ACQUIRE_CAPABILITY(__margs...)
@@ -484,20 +482,14 @@ public:
: __t_(__margs...) {}
_LIBCPP_RELEASE_CAPABILITY() _LIBCPP_HIDE_FROM_ABI ~scoped_lock() {
- __unlock_unpack(make_index_sequence<sizeof...(_MArgs)>(), __t_);
+ _TupleT::__apply(__t_, [] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS(auto&... __args) { (__args.unlock(), ...); });
}
scoped_lock(scoped_lock const&) = delete;
scoped_lock& operator=(scoped_lock const&) = delete;
private:
- template <size_t... _Indx>
- _LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(index_sequence<_Indx...>, _MutexTuple& __mt)
- _LIBCPP_RELEASE_CAPABILITY(std::get<_Indx>(__mt)...) {
- (std::get<_Indx>(__mt).unlock(), ...);
- }
-
- _MutexTuple __t_;
+ _TupleT __t_;
};
_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);
@@ -510,6 +502,10 @@ _LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
+# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
+# include <tuple>
+# endif
+
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP_MUTEX
diff --git a/libcxx/include/numeric b/libcxx/include/numeric
index 876d36421f43c..6566fd72ece92 100644
--- a/libcxx/include/numeric
+++ b/libcxx/include/numeric
@@ -192,7 +192,9 @@ constexpr T saturating_cast(U x) noexcept; // freestanding, S
# 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_NUMERIC
diff --git a/libcxx/include/tuple b/libcxx/include/tuple
index 2f0127bc7388d..e23ac88c9cdd1 100644
--- a/libcxx/include/tuple
+++ b/libcxx/include/tuple
@@ -660,8 +660,8 @@ public:
// the two conditions below are not in spec. The purpose is to disable the UTypes Ctor when copy/move Ctor
// can work. Otherwise, is_constructible can trigger hard error in those cases
// https://godbolt.org/z/M94cGdKcE
- _Not<is_same<_OtherTuple, const tuple&> >,
- _Not<is_same<_OtherTuple, tuple&&> >,
+ _IsNotSame<_OtherTuple, const tuple&>,
+ _IsNotSame<_OtherTuple, tuple&&>,
is_constructible<_Tp, __copy_cvref_t<_OtherTuple, _Up> >...,
_Or<_BoolConstant<sizeof...(_Tp) != 1>,
// _Tp and _Up are 1-element packs - the pack expansions look
diff --git a/libcxx/include/vector b/libcxx/include/vector
index f2ae5ad4aed28..66fc67cc165f7 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -348,6 +348,10 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
# pragma GCC system_header
# endif
+# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 14
+# include <tuple>
+# endif
+
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP_VECTOR
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 62b58acd1e58e..d09947ff7d297 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -1,6 +1,5 @@
algorithm cctype
algorithm climits
-algorithm compare
algorithm cstdint
algorithm cstring
algorithm ctime
@@ -10,7 +9,6 @@ algorithm initializer_list
algorithm iosfwd
algorithm limits
algorithm ratio
-algorithm tuple
algorithm version
any cstdint
any initializer_list
@@ -645,19 +643,16 @@ memory_resource tuple
memory_resource version
mutex cerrno
mutex climits
-mutex compare
mutex cstdint
mutex cstring
mutex ctime
mutex limits
mutex ratio
-mutex tuple
mutex version
new version
numbers version
numeric cctype
numeric climits
-numeric compare
numeric cstdint
numeric cstring
numeric ctime
@@ -666,7 +661,6 @@ numeric cwctype
numeric initializer_list
numeric limits
numeric ratio
-numeric tuple
numeric version
optional compare
optional cstdint
diff --git a/libcxx/test/std/thread/futures/futures.async/async.verify.cpp b/libcxx/test/std/thread/futures/futures.async/async.verify.cpp
index 2cb15a79ae089..16307a1082003 100644
--- a/libcxx/test/std/thread/futures/futures.async/async.verify.cpp
+++ b/libcxx/test/std/thread/futures/futures.async/async.verify.cpp
@@ -40,8 +40,7 @@ void f() {
F f;
static_cast<void>(std::async(f));
// expected-error@*:* {{static assertion failed}}
- // expected-error@*:* {{no matching constructor for initialization}}
- // expected-error@*:* 0-1 {{call to deleted constructor}}
+ // expected-error@*:* 0-2 {{call to deleted constructor}}
}
{ // Mandates: is_constructible_v<decay_t<F>, F>
@@ -55,8 +54,7 @@ void f() {
static_cast<void>(std::async(F{}));
// expected-error@*:* {{static assertion failed}}
- // expected-error@*:* {{no matching constructor for initialization}}
- // expected-error@*:* 0-1 {{call to deleted constructor}}
+ // expected-error@*:* 0-2 {{call to deleted constructor}}
}
{ // Mandates: (is_constructible_v<decay_t<Args>, Args> && ...)
diff --git a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp
index 6a63b65bf148e..c916d4f83c7b2 100644
--- a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp
@@ -68,9 +68,9 @@ void test() {
Arg x;
auto f = std::bind_back([](const Arg&) {}, x);
// expected-error-re@*:* {{static assertion failed{{.*}}bind_back requires all decay_t<Args> to be constructible from respective Args}}
- // expected-error@*:* {{no matching constructor for initialization}}
// expected-error@*:* 0-1{{call to deleted constructor of 'F'}}
- // expected-error@*:* 0-1{{call to deleted constructor of 'Arg'}}
+ // expected-error@*:* 0-2{{call to deleted constructor of 'Arg'}}
+ // expected-error@*:* {{no matching constructor}}
}
{ // Mandates: (is_move_constructible_v<decay_t<Args>> && ...)
diff --git a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp
index d7ed90f87562b..185c13cc37bf1 100644
--- a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.nttp.verify.cpp
@@ -35,7 +35,7 @@ void test() {
Arg arg;
auto _ = std::bind_front<AnyArgs{}>(arg);
// expected-error@*:* {{static assertion failed due to requirement 'is_constructible_v<Arg, Arg &>': bind_front requires all decay_t<Args> to be constructible from respective Args}}
- // expected-error@*:* 0-1{{call to deleted constructor of 'Arg'}}
+ // expected-error@*:* 0-2{{call to deleted constructor of 'Arg'}}
}
{ // (is_move_constructible_v<BoundArgs> && ...) is true
More information about the libcxx-commits
mailing list