|
1 | 1 | #pragma once
|
2 | 2 |
|
3 | 3 | #include "../type_traits/indexed_traits.h"
|
| 4 | +#include "invoke.h" |
4 | 5 |
|
5 |
| -#include <algorithm> |
6 |
| -#include <functional> |
| 6 | +#include <tuple> |
7 | 7 |
|
8 | 8 | #include "../compilation_config_in.h"
|
9 | 9 |
|
10 |
| -namespace stdsharp::details |
11 |
| -{ |
12 |
| - template<typename... Func> |
13 |
| - struct invocables_traits |
14 |
| - { |
15 |
| - template<typename = std::index_sequence_for<Func...>> |
16 |
| - struct impl; |
17 |
| - |
18 |
| - using type = impl<>; |
19 |
| - |
20 |
| - template<std::size_t I> |
21 |
| - struct indexed_operator |
22 |
| - { |
23 |
| - template< |
24 |
| - typename Self, |
25 |
| - typename... Args, |
26 |
| - std::invocable<Args...> Fn = get_element_t<I, forward_cast_t<Self, type>>> |
27 |
| - constexpr decltype(auto) operator()(this Self&& self, Args&&... args) |
28 |
| - noexcept(nothrow_invocable<Fn, Args...>) |
29 |
| - { |
30 |
| - return invoke( |
31 |
| - cpo::get_element<I>(forward_cast<Self, type>(self)), |
32 |
| - cpp_forward(args)... |
33 |
| - ); |
34 |
| - } |
35 |
| - }; |
36 |
| - |
37 |
| - using indexed_values = stdsharp::indexed_values<Func...>; |
38 |
| - |
39 |
| - template<std::size_t... I> |
40 |
| - struct STDSHARP_EBO impl<std::index_sequence<I...>> : indexed_values, indexed_operator<I>... |
41 |
| - { |
42 |
| - using indexed_values::indexed_values; |
43 |
| - using indexed_operator<I>::operator()...; |
44 |
| - }; |
45 |
| - }; |
46 |
| -} |
47 | 10 |
|
48 | 11 | namespace stdsharp
|
49 | 12 | {
|
50 |
| - template<typename... Func> |
51 |
| - struct invocables : details::invocables_traits<Func...>::type |
| 13 | + template<std::size_t I, typename Func> |
| 14 | + struct indexed_invocable : value_wrapper<Func> |
52 | 15 | {
|
53 |
| - private: |
54 |
| - using m_invocables = details::invocables_traits<Func...>::type; |
55 |
| - |
56 |
| - public: |
57 |
| - template<typename... Args> |
58 |
| - requires std::constructible_from<m_invocables, Args...> |
59 |
| - constexpr invocables(Args&&... args) |
60 |
| - noexcept(nothrow_constructible_from<m_invocables, Args...>): |
61 |
| - m_invocables(cpp_forward(args)...) |
| 16 | + template< |
| 17 | + typename Self, |
| 18 | + typename... Args, |
| 19 | + std::invocable<Args...> Fn = forward_cast_t<Self, Func>> |
| 20 | + constexpr decltype(auto) operator()(this Self&& self, Args&&... args) |
| 21 | + noexcept(nothrow_invocable<Fn, Args...>) |
62 | 22 | {
|
| 23 | + return invoke(forward_cast<Self, indexed_invocable, Func>(self), cpp_forward(args)...); |
63 | 24 | }
|
64 |
| - |
65 |
| - invocables() = default; |
66 | 25 | };
|
| 26 | +} |
67 | 27 |
|
68 |
| - template<typename... T> |
69 |
| - invocables(T&&...) -> invocables<std::decay_t<T>...>; |
| 28 | +namespace stdsharp::details |
| 29 | +{ |
| 30 | + template<typename...> |
| 31 | + struct invocables; |
70 | 32 |
|
71 |
| - template<std::size_t Index> |
72 |
| - struct invoke_at_fn |
| 33 | + template<typename... Func, std::size_t... I> |
| 34 | + struct STDSHARP_EBO invocables<std::index_sequence<I...>, Func...> : |
| 35 | + indexed_invocable<I, Func>... |
73 | 36 | {
|
74 |
| - template<typename T, typename... Args> |
75 |
| - requires std::invocable<get_element_t<Index, T>, Args...> |
76 |
| - constexpr decltype(auto) operator()(T&& t, Args&&... args) const |
77 |
| - noexcept(nothrow_invocable<get_element_t<Index, T>, Args...>) |
78 |
| - { |
79 |
| - return cpo::get_element<Index>(t)(cpp_forward(args)...); |
80 |
| - } |
81 |
| - }; |
| 37 | + static constexpr auto size() noexcept { return sizeof...(Func); } |
82 | 38 |
|
83 |
| - template<auto Index> |
84 |
| - inline constexpr invoke_at_fn<Index> invoke_at{}; |
| 39 | + template<std::size_t J> |
| 40 | + using type = type_at<J, Func...>; |
85 | 41 |
|
86 |
| - template<template<typename> typename Predicator> |
87 |
| - struct invoke_first_fn |
88 |
| - { |
89 |
| - private: |
90 |
| - template<typename T, typename... Args, std::size_t I = 0> |
91 |
| - static constexpr std::size_t find_first(const index_constant<I> /*unused*/ = {}) noexcept |
| 42 | + template<std::size_t J, typename Self> |
| 43 | + constexpr forward_cast_t<Self, type<J>> get(this Self&& self) noexcept |
92 | 44 | {
|
93 |
| - if constexpr( // |
94 |
| - requires { |
95 |
| - requires I < std::tuple_size_v<std::decay_t<T>>; |
96 |
| - typename get_element_t<I, T>; |
97 |
| - } // |
98 |
| - ) |
99 |
| - if constexpr(Predicator<get_element_t<I, T>>::template value<Args...>) return I; |
100 |
| - else return find_first<T, Args...>(index_constant<I + 1>{}); |
101 |
| - else return static_cast<std::size_t>(-1); |
| 45 | + return forward_cast<Self, invocables, indexed_value<J, type<J>>>(self).get(); |
102 | 46 | }
|
103 | 47 |
|
104 |
| - template<typename T, typename... Args> |
105 |
| - static constexpr auto index = find_first<T, Args...>(); |
106 |
| - |
107 |
| - template<typename T, typename... Args> |
108 |
| - requires(index<T, Args...> != -1) |
109 |
| - using invoke_at_t = invoke_at_fn<index<T, Args...>>; |
110 |
| - |
111 |
| - public: |
112 |
| - template<typename T, typename... Args> |
113 |
| - requires requires { typename invoke_at_t<T, Args...>; } |
114 |
| - constexpr decltype(auto) operator()(T&& t, Args&&... args) const |
115 |
| - noexcept(nothrow_invocable<invoke_at_t<T, Args...>, T, Args...>) |
| 48 | + template<std::size_t J, typename Self, typename SelfT = const Self> |
| 49 | + constexpr forward_cast_t<SelfT, type<J>> cget(this const Self&& self) noexcept |
116 | 50 | {
|
117 |
| - return invoke_at_t<T, Args...>{}(t, cpp_forward(args)...); |
| 51 | + return forward_cast<SelfT, invocables, indexed_value<J, type<J>>>(self).cget(); |
118 | 52 | }
|
119 |
| - }; |
120 |
| - |
121 |
| - template<template<typename> typename Predicator> |
122 |
| - inline constexpr invoke_first_fn<Predicator> invoke_first{}; |
123 |
| - |
124 |
| - namespace details |
125 |
| - { |
126 |
| - template<typename Func> |
127 |
| - struct sequenced_invocables_predicate |
128 |
| - { |
129 |
| - template<typename... Args> |
130 |
| - static constexpr auto value = std::invocable<Func, Args...>; |
131 |
| - }; |
132 |
| - } |
133 |
| - |
134 |
| - using sequenced_invoke_fn = invoke_first_fn<details::sequenced_invocables_predicate>; |
135 |
| - |
136 |
| - inline constexpr sequenced_invoke_fn sequenced_invoke{}; |
137 |
| - |
138 |
| - template<typename... Invocable> |
139 |
| - struct sequenced_invocables : invocables<Invocable...> |
140 |
| - { |
141 |
| - using base = invocables<Invocable...>; |
142 |
| - |
143 |
| - using base::base; |
144 |
| - |
145 |
| - sequenced_invocables() = default; |
146 | 53 |
|
147 |
| - template<typename Self, typename... Args, typename Base = forward_cast_t<Self, base>> |
148 |
| - requires std::invocable<sequenced_invoke_fn, Base, Args...> |
149 |
| - constexpr decltype(auto) operator()(this Self&& self, Args&&... args) |
150 |
| - noexcept(nothrow_invocable<sequenced_invoke_fn, Base, Args...>) |
| 54 | + template<std::size_t J, typename Self, typename SelfT = const Self&> |
| 55 | + constexpr forward_cast_t<SelfT, type<J>> cget(this const Self& self) noexcept |
151 | 56 | {
|
152 |
| - return sequenced_invoke( |
153 |
| - forward_cast<Self, sequenced_invocables, base>(self), |
154 |
| - cpp_forward(args)... |
155 |
| - ); |
| 57 | + return forward_cast<SelfT, invocables, indexed_value<J, type<J>>>(self).cget(); |
156 | 58 | }
|
157 | 59 | };
|
| 60 | +} |
158 | 61 |
|
159 |
| - template<typename... T> |
160 |
| - sequenced_invocables(T&&...) -> sequenced_invocables<std::decay_t<T>...>; |
161 |
| - |
162 |
| - template<typename Func> |
163 |
| - struct nodiscard_invocable : invocables<Func> |
| 62 | +namespace stdsharp |
| 63 | +{ |
| 64 | + template<typename... Func> |
| 65 | + struct invocables : details::invocables<std::index_sequence_for<Func...>, Func...> |
164 | 66 | {
|
165 |
| - using base = invocables<Func>; |
166 |
| - |
167 |
| - using base::base; |
168 |
| - |
169 |
| - template<typename Self, typename... Args, typename Base = forward_cast_t<Self, base>> |
170 |
| - requires std ::invocable<Base, Args...> |
171 |
| - [[nodiscard]] constexpr decltype(auto) operator()(this Self&& self, Args&&... args) |
172 |
| - noexcept(nothrow_invocable<Base, Args...>) |
173 |
| - { |
174 |
| - return forward_cast<Self, nodiscard_invocable, base>(self)(cpp_forward(args)...); |
175 |
| - } |
176 | 67 | };
|
177 | 68 |
|
178 |
| - template<typename Func> |
179 |
| - nodiscard_invocable(Func&&) -> nodiscard_invocable<std::decay_t<Func>>; |
| 69 | + template<typename... T> |
| 70 | + invocables(T&&...) -> invocables<std::decay_t<T>...>; |
180 | 71 | }
|
181 | 72 |
|
182 | 73 | namespace std
|
183 | 74 | {
|
184 | 75 | template<typename... T>
|
185 |
| - struct tuple_size<::stdsharp::invocables<T...>> : |
186 |
| - ::std::tuple_size<::stdsharp::indexed_types<T...>> |
187 |
| - { |
188 |
| - }; |
189 |
| - |
190 |
| - template<std::size_t I, typename... T> |
191 |
| - struct tuple_element<I, ::stdsharp::invocables<T...>> : |
192 |
| - ::std::tuple_element<I, ::stdsharp::indexed_types<T...>> |
193 |
| - { |
194 |
| - }; |
195 |
| - |
196 |
| - template<typename... T> |
197 |
| - struct tuple_size<::stdsharp::sequenced_invocables<T...>> : |
198 |
| - ::std::tuple_size<::stdsharp::invocables<T...>> |
| 76 | + struct tuple_size<::stdsharp::invocables<T...>> |
199 | 77 | {
|
| 78 | + static constexpr auto value = ::stdsharp::invocables<T...>::size(); |
200 | 79 | };
|
201 | 80 |
|
202 | 81 | template<std::size_t I, typename... T>
|
203 |
| - struct tuple_element<I, ::stdsharp::sequenced_invocables<T...>> : |
204 |
| - ::std::tuple_element<I, ::stdsharp::invocables<T...>> |
| 82 | + struct tuple_element<I, ::stdsharp::invocables<T...>> |
205 | 83 | {
|
| 84 | + using type = ::stdsharp::invocables<T...>::template type<I>; |
206 | 85 | };
|
207 | 86 | }
|
208 | 87 |
|
|
0 commit comments