1 /*
2 * Copyright (c) 2023 NVIDIA Corporation
3 *
4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * https://llvm.org/LICENSE.txt
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include "__concepts.hpp"
19 #include "__config.hpp"
20 #include "__meta.hpp"
21 #include "__type_traits.hpp"
22
23 #include <cstddef>
24
25 namespace stdexec
26 {
27 namespace __tup
28 {
29 template <class _Ty, std::size_t _Idx>
30 struct __box
31 {
32 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Ty __value;
33 };
34
35 template <class _Idx, class... _Ts>
36 struct __tuple;
37
38 template <std::size_t... _Idx, class... _Ts>
39 struct __tuple<__indices<_Idx...>, _Ts...> : __box<_Ts, _Idx>...
40 {};
41
42 template <class... _Ts>
43 STDEXEC_ATTRIBUTE((host, device))
44 __tuple(_Ts...) -> __tuple<__indices_for<_Ts...>, _Ts...>;
45
46 #if STDEXEC_GCC()
47 template <class... _Ts>
48 struct __mk_tuple
49 {
50 using __t = __tuple<__indices_for<_Ts...>, _Ts...>;
51 };
52 template <class... _Ts>
53 using __tuple_for = __t<__mk_tuple<_Ts...>>;
54 #else
55 template <class... _Ts>
56 using __tuple_for = __tuple<__indices_for<_Ts...>, _Ts...>;
57 #endif
58
59 template <std::size_t _Idx, class _Ty>
60 STDEXEC_ATTRIBUTE((always_inline))
__get(__box<_Ty,_Idx> && __self)61 constexpr _Ty&& __get(__box<_Ty, _Idx>&& __self) noexcept
62 {
63 return static_cast<_Ty&&>(__self.__value);
64 }
65
66 template <std::size_t _Idx, class _Ty>
67 STDEXEC_ATTRIBUTE((always_inline))
__get(__box<_Ty,_Idx> & __self)68 constexpr _Ty& __get(__box<_Ty, _Idx>& __self) noexcept
69 {
70 return __self.__value;
71 }
72
73 template <std::size_t _Idx, class _Ty>
74 STDEXEC_ATTRIBUTE((always_inline))
__get(const __box<_Ty,_Idx> & __self)75 constexpr const _Ty& __get(const __box<_Ty, _Idx>& __self) noexcept
76 {
77 return __self.__value;
78 }
79
80 template <std::size_t... _Idx, class... _Ts>
81 void __tuple_like_(const __tuple<__indices<_Idx...>, _Ts...>&);
82
83 template <class _Tup>
84 concept __tuple_like = requires(_Tup& __tup) { __tup::__tuple_like_(__tup); };
85
86 struct __apply_
87 {
88 template <class _Fun, class _Tuple, std::size_t... _Idx, class... _Ts>
89 requires __callable<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
operator ()stdexec::__tup::__apply_90 constexpr auto operator()(
91 _Fun&& __fun, _Tuple&& __tup,
92 const __tuple<
93 __indices<_Idx...>,
94 _Ts...>*) noexcept(__nothrow_callable<_Fun, __copy_cvref_t<_Tuple,
95 _Ts>...>)
96 -> __call_result_t<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
97 {
98 return static_cast<_Fun&&>(__fun)(
99 static_cast<__copy_cvref_t<_Tuple, __box<_Ts, _Idx>>&&>(__tup)
100 .__value...);
101 }
102 };
103
104 template <class _Fun, __tuple_like _Tuple>
105 STDEXEC_ATTRIBUTE((always_inline))
__apply(_Fun && __fun,_Tuple && __tup)106 constexpr auto __apply(_Fun&& __fun, _Tuple&& __tup) noexcept(
107 noexcept(__apply_()(static_cast<_Fun&&>(__fun),
108 static_cast<_Tuple&&>(__tup), &__tup)))
109 -> decltype(__apply_()(static_cast<_Fun&&>(__fun),
110 static_cast<_Tuple&&>(__tup), &__tup))
111 {
112 return __apply_()(static_cast<_Fun&&>(__fun), static_cast<_Tuple&&>(__tup),
113 &__tup);
114 }
115 } // namespace __tup
116
117 using __tup::__tuple;
118
119 // So we can use __tuple as a typelist and ignore the first template parameter
120 template <class _Fn, class _Idx, class... _Ts>
121 requires __minvocable<_Fn, _Ts...>
122 struct __uncurry_<_Fn, __tuple<_Idx, _Ts...>>
123 {
124 using __t = __minvoke<_Fn, _Ts...>;
125 };
126 } // namespace stdexec
127