blob: d5939f5c2cf7967d7a541ef541a79c7d8d7ddb27 [file] [log] [blame]
Patrick Williams4c2d73d2023-12-01 16:58:58 -06001/*
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
Patrick Williams8723a542024-02-12 11:18:32 -060018#include "__concepts.hpp"
Patrick Williams4c2d73d2023-12-01 16:58:58 -060019#include "__config.hpp"
20#include "__meta.hpp"
Patrick Williams8723a542024-02-12 11:18:32 -060021#include "__type_traits.hpp"
22
23#include <cstddef>
Patrick Williams4c2d73d2023-12-01 16:58:58 -060024
25namespace stdexec
26{
27namespace __tup
28{
29template <class _Ty, std::size_t _Idx>
30struct __box
31{
32 STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS _Ty __value;
33};
34
35template <class _Idx, class... _Ts>
36struct __tuple;
37
38template <std::size_t... _Idx, class... _Ts>
39struct __tuple<__indices<_Idx...>, _Ts...> : __box<_Ts, _Idx>...
40{};
41
42template <class... _Ts>
43STDEXEC_ATTRIBUTE((host, device))
44__tuple(_Ts...) -> __tuple<__indices_for<_Ts...>, _Ts...>;
45
46#if STDEXEC_GCC()
47template <class... _Ts>
48struct __mk_tuple
49{
50 using __t = __tuple<__indices_for<_Ts...>, _Ts...>;
51};
52template <class... _Ts>
53using __tuple_for = __t<__mk_tuple<_Ts...>>;
54#else
55template <class... _Ts>
56using __tuple_for = __tuple<__indices_for<_Ts...>, _Ts...>;
57#endif
58
59template <std::size_t _Idx, class _Ty>
60STDEXEC_ATTRIBUTE((always_inline))
61constexpr _Ty&& __get(__box<_Ty, _Idx>&& __self) noexcept
62{
63 return (_Ty&&)__self.__value;
64}
65
66template <std::size_t _Idx, class _Ty>
67STDEXEC_ATTRIBUTE((always_inline))
68constexpr _Ty& __get(__box<_Ty, _Idx>& __self) noexcept
69{
70 return __self.__value;
71}
72
73template <std::size_t _Idx, class _Ty>
74STDEXEC_ATTRIBUTE((always_inline))
75constexpr const _Ty& __get(const __box<_Ty, _Idx>& __self) noexcept
76{
77 return __self.__value;
78}
79
80template <std::size_t... _Idx, class... _Ts>
81void __tuple_like_(const __tuple<__indices<_Idx...>, _Ts...>&);
82
83template <class _Tup>
84concept __tuple_like = requires(_Tup& __tup) { __tup::__tuple_like_(__tup); };
85
86struct __apply_
87{
88 template <class _Fun, class _Tuple, std::size_t... _Idx, class... _Ts>
89 requires __callable<_Fun, __copy_cvref_t<_Tuple, _Ts>...>
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 ((_Fun&&)__fun)(
99 static_cast<__copy_cvref_t<_Tuple, __box<_Ts, _Idx>>&&>(__tup)
100 .__value...);
101 }
102};
103
104template <class _Fun, __tuple_like _Tuple>
105STDEXEC_ATTRIBUTE((always_inline))
106constexpr auto __apply(_Fun&& __fun, _Tuple&& __tup) noexcept(
107 noexcept(__apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup)))
108 -> decltype(__apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup))
109{
110 return __apply_()((_Fun&&)__fun, (_Tuple&&)__tup, &__tup);
111}
112} // namespace __tup
113
114using __tup::__tuple;
115
116// So we can use __tuple as a typelist and ignore the first template parameter
117template <class _Fn, class _Idx, class... _Ts>
118 requires __minvocable<_Fn, _Ts...>
119struct __uncurry_<_Fn, __tuple<_Idx, _Ts...>>
120{
121 using __t = __minvoke<_Fn, _Ts...>;
122};
123} // namespace stdexec