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