capydi
Loading...
Searching...
No Matches
ValuedPackFor.hpp
Go to the documentation of this file.
1#ifndef PACK_ALGORITHM_HPP_
2#define PACK_ALGORITHM_HPP_
3
5#include "legacy/PackMap.hpp"
6#include "legacy/Head.hpp"
9
10#include <tuple>
11#include <type_traits>
12#include <functional>
13#include <expected>
14
15namespace capy::meta
16{
17
19
21{
22 template<typename... Types>
23 struct AllSame;
24
25 template<typename Head, typename... Tail>
26 struct AllSame<Head, Tail...>
27 : std::conjunction<std::is_same<Head, Tail>...>
28 {};
29
30 template<>
31 struct AllSame<>
32 : std::true_type
33 {};
34
35 template<typename... Types>
36 using all_same_v = AllSame<Types...>::value;
37
38 template<typename Handler, typename... PackElements>
39 struct ValuedPackForResult
40 {
41 private:
42 template<typename Expected>
43 struct ValueTypeMapper
44 {
45 using type = typename Expected::value_type;
46 };
47
48 template<typename Expected>
49 struct ErrorTypeMapper
50 {
51 using type = typename Expected::error_type;
52 };
53
54 using ResultsPack = Pack<
55 typename std::invoke_result_t<
56 Handler,
57 Unit<PackElements>
58 >...
59 >;
60
61 using SuccessSubtypesPack = legacy::pack_map_t<
62 ResultsPack,
63 ValueTypeMapper
64 >;
65
66 using ErrorSubtypesPack = legacy::pack_map_t<
67 ResultsPack,
68 ErrorTypeMapper
69 >;
70
71 static constexpr bool all_error_types_same =
72 rebind_pack_t<ErrorSubtypesPack, AllSame>::value;
73
74 static_assert(all_error_types_same, "All error types must be equal");
75
76 using SuccessType = rebind_pack_t<SuccessSubtypesPack, std::tuple>;
77 using ErrorType = legacy::head_t<ErrorSubtypesPack>; // None if empty
78
79 public:
80 using type = std::expected<SuccessType, ErrorType>;
81 };
82
83 template<typename Handler, typename... PackElements>
84 using valued_pack_for_result_t = typename ValuedPackForResult<
85 Handler,
86 PackElements...
87 >::type;
88
89 template<
90 typename Handler,
91 typename AccumulatedResult,
92 typename ErrorType,
93 typename TypesPack
94 >
95 struct ValuedPackForUtilityResult;
96
97 template<
98 typename Handler,
99 typename AccumulatedResult,
100 typename ErrorType_,
101 typename... Types
102 >
103 struct ValuedPackForUtilityResult
104 <
105 Handler,
106 AccumulatedResult,
107 ErrorType_,
108 Pack<Types...>
109 >
110 {
111 private:
112 template<typename Expected>
113 struct ValueTypeMapper
114 {
115 using type = typename Expected::value_type;
116 };
117
118 using AccumulatedResultPack = rebind_t<
119 AccumulatedResult,
120 std::tuple,
121 Pack
122 >;
123
124 using NextTypesPack = Pack<
125 typename std::invoke_result_t<
126 Handler,
127 Unit<Types>
128 >...
129 >;
130
131 using NextSuccessTypesPack = legacy::pack_map_t<
132 NextTypesPack,
133 ValueTypeMapper
134 >;
135
136 using SuccessSubtypesPack = legacy::pack_concat_t<
137 AccumulatedResultPack,
138 NextSuccessTypesPack
139 >;
140
141 using SuccessType = rebind_pack_t<SuccessSubtypesPack, std::tuple>;
142 using ErrorType = ErrorType_; // None if empty
143
144 public:
145 using type = std::expected<SuccessType, ErrorType>;
146 };
147
148 template<
149 typename Handler,
150 typename AccumulatedResult,
151 typename ErrorType,
152 typename TypesPack
153 >
154 using valued_pack_for_utility_result_t = typename ValuedPackForUtilityResult<
155 Handler,
156 AccumulatedResult,
157 ErrorType,
158 TypesPack
159 >::type;
160
161 template<
162 typename Handler,
163 typename AccumulatedResult,
164 typename ErrorType
165 >
166 constexpr inline std::expected<AccumulatedResult, ErrorType> valued_pack_for_utility__(
167 Pack<>&& pack,
168 Handler&& handler,
169 AccumulatedResult&& accumulated_result,
170 Unit<ErrorType> error_type
171 ) {
172 return std::forward<AccumulatedResult>(accumulated_result);
173 }
174
175 template<
176 typename Handler,
177 typename AccumulatedResult,
178 typename ErrorType,
179 typename Head, typename... Tail
180 >
181 constexpr inline valued_pack_for_utility_result_t<
182 Handler,
183 AccumulatedResult,
184 ErrorType,
185 Pack<Head, Tail...>
186 > valued_pack_for_utility__(
187 Pack<Head, Tail...>&& pack,
188 Handler&& handler,
189 AccumulatedResult&& accumulated_result,
190 Unit<ErrorType>&& error_type
191 ) {
192 auto /* std::expected */ handler_result =
193 std::invoke(handler, Unit<Head>{});
194
195 if (!handler_result.has_value()) [[unlikely]]
196 {
197 return std::unexpected(handler_result.error());
198 }
199
200 auto successful_handling_result = handler_result.value();
201
202 auto next_accumulated_result = std::tuple_cat(
203 std::forward<AccumulatedResult>(accumulated_result),
204 std::tuple { successful_handling_result }
205 );
206
207 return valued_pack_for_utility__(
208 Pack<Tail...>{},
209 std::forward<Handler>(handler),
210 std::move(next_accumulated_result),
211 std::move(error_type)
212 );
213 }
214}
215
217
218template<typename Handler, typename... PackElements>
219constexpr implementation_details_::valued_pack_for_result_t<
220 Handler, PackElements...
222 Pack<PackElements...>&& pack,
223 Handler&& handler
224) {
225 using ReturnType = decltype(valued_pack_for(
226 std::move(pack),
227 std::forward<Handler>(handler)
228 ));
229
230 return implementation_details_::valued_pack_for_utility__(
231 std::move(pack),
232 std::forward<Handler>(handler),
233 std::tuple{},
235 );
236}
237
238}
239
240#endif // !PACK_ALGORITHM_HPP_
Compile-time type pack utilities and metaprogramming foundations.
Definition Rebind.hpp:7
typename typed__::Rebind< Type, SrcContainer, DstContainer >::type rebind_t
Definition Rebind.hpp:121
constexpr implementation_details_::valued_pack_for_result_t< Handler, PackElements... > valued_pack_for(Pack< PackElements... > &&pack, Handler &&handler)
Definition ValuedPackFor.hpp:221
A compile-time heterogeneous type list.
Definition Pack.hpp:70
A zero-cost wrapper for forwarding compile-time type information.
Definition Pack.hpp:45