VCCC  2024.05
VisualCamp Common C++ library
monadic.hpp
Go to the documentation of this file.
1 //
2 // Created by YongGyu Lee on 3/28/24.
3 //
4 
5 #ifndef VCCC_EXPECTED_MONADIC_HPP_
6 #define VCCC_EXPECTED_MONADIC_HPP_
7 
8 #include <type_traits>
9 #include <utility>
10 
20 
21 namespace vccc {
22 namespace detail {
23 
24 template<bool Void /* true */, typename T, template<typename...> class Test, typename... U>
25 struct void_or_impl : std::true_type {};
26 
27 template<typename T, template<typename...> class Test, typename... U>
28 struct void_or_impl<false, T, Test, U...> : Test<U...> {};
29 
30 template<typename T, template<typename...> class Test, typename... U>
31 using void_or = void_or_impl<std::is_void<T>::value, T, Test, U...>;
32 
33 template<typename T, typename = void>
34 struct has_typename_error_type : std::false_type {};
35 
36 template<typename T>
37 struct has_typename_error_type<T, void_t<typename T::error_type>> : std::true_type {};
38 
39 template<typename T>
40 struct expected_valid_value_type
41  : conjunction<
42  negation<std::is_reference<T>>,
43  negation<std::is_array<T>>,
44  negation<std::is_function<T>>,
45  negation<is_specialization<T, unexpected>>,
46  negation<std::is_same<std::remove_cv_t<T>, in_place_t>>,
47  negation<std::is_same<std::remove_cv_t<T>, unexpect_t>>
48  > {};
49 
50 template<typename E>
51 struct expected_valid_error_type
52  : conjunction<
53  std::is_object<E>,
54  negation<std::is_array<E>>,
55  negation<is_specialization<E, unexpected>>,
56  negation<std::is_const<E>>,
57  negation<std::is_volatile<E>>
58  >{};
59 
60 template<typename E>
61 struct expected_is_void : std::is_void<typename remove_cvref_t<E>::value_type> {};
62 
64 struct expected_value_invocable
65  : is_invocable<F> {};
66 
67 template<typename F, typename Expected>
68 struct expected_value_invocable<F, Expected, false>
69  : is_invocable<F, decltype(*std::declval<Expected>())> {};
70 
71 template<typename F, typename Expected>
72 struct expected_error_invocable
73  : is_invocable<F, decltype(std::declval<Expected>().error())>{};
74 
76 struct expected_value_invoke_result {
77  using type = invoke_result_t<F>;
78 };
79 
80 template<typename F, typename Expected>
81 struct expected_value_invoke_result<F, Expected, false> {
82  using type = invoke_result_t<F, decltype(*std::declval<Expected>())>;
83 };
84 
85 template<typename F, typename Expected>
86 using expected_value_invoke_result_t = typename expected_value_invoke_result<F, Expected>::type;
87 
88 template<typename F, typename Expected>
89 using expected_error_invoke_result_t = invoke_result_t<F, decltype(std::declval<Expected>().error())>;
90 
91 template<typename F, typename Expected, std::enable_if_t<
92  expected_is_void<Expected>::value == true, int> = 0>
93 constexpr decltype(auto) expected_value_invoke(F&& f, Expected&&) {
94  return vccc::invoke(std::forward<F>(f));
95 }
96 
97 template<typename F, typename Expected, std::enable_if_t<
98  expected_is_void<Expected>::value == false, int> = 0>
99 constexpr decltype(auto) expected_value_invoke(F&& f, Expected&& e) {
100  return vccc::invoke(std::forward<F>(f), *std::forward<Expected>(e));
101 }
102 
103 template<typename Expected>
104 class expected_and_then_t;
105 
106 template<template<typename, typename> class Expected, typename T, typename E>
107 class expected_and_then_t<Expected<T, E>> {
108  template<typename F, typename Self>
109  using U = remove_cvref_t<expected_value_invoke_result_t<F, Self>>;
110 
111  public:
112  template<typename F, typename Self, std::enable_if_t<conjunction<
113  expected_value_invocable<F, Self>,
114  is_specialization<U<F, Self>, Expected>,
115  has_typename_error_type<U<F, Self>>,
116  std::is_same<typename U<F, Self>::error_type, E>
117  >::value, int> = 0>
118  constexpr auto operator()(F&& f, Self&& self) const {
119  if (self.has_value()) {
120  return expected_value_invoke(std::forward<F>(f), std::forward<Self>(self));
121  } else {
122  return U<F, Self>(unexpect, std::forward<Self>(self).error());
123  }
124  }
125 };
126 
127 template<typename Expected>
128 class expected_transform_t;
129 
130 template<template<typename, typename> class Expected, typename T, typename E>
131 class expected_transform_t<Expected<T, E>> {
132  template<typename F, typename Self>
133  using U = std::remove_cv_t<expected_value_invoke_result_t<F, Self>>;
134 
135  template<typename F, typename Self>
136  constexpr auto valued(F&& f, Self&& self, std::true_type /* void */) const {
137  expected_value_invoke(std::forward<F>(f), std::forward<Self>(self));
138  return Expected<U<F, Self>, E>();
139  }
140 
141  template<typename F, typename Self>
142  constexpr auto valued(F&& f, Self&& self, std::false_type /* void */) const {
143  return Expected<U<F, Self>, E>(expected_value_invoke(std::forward<F>(f), std::forward<Self>(self)));
144  }
145 
146  public:
147  template<typename F, typename Self, std::enable_if_t<conjunction<
148  expected_value_invocable<F, Self>,
149  expected_valid_value_type<U<F, Self>>,
150  void_or<T, std::is_constructible, U<F, Self>, expected_value_invoke_result_t<F, Self>>
151  >::value, int> = 0>
152  constexpr auto operator()(F&& f, Self&& self) const {
153  if (self.has_value()) {
154  return valued(std::forward<F>(f), std::forward<Self>(self), std::is_void<T>{});
155  } else {
156  return Expected<U<F, Self>, E>(unexpect, std::forward<Self>(self).error());
157  }
158  }
159 };
160 
161 template<typename Expected>
162 class expected_or_else_t;
163 
164 template<template<typename, typename> class Expected, typename T, typename E>
165 class expected_or_else_t<Expected<T, E>> {
166  template<typename F, typename Self>
167  using G = remove_cvref_t<expected_error_invoke_result_t<F, Self>>;
168 
169  template<typename F, typename Self>
170  constexpr auto valued(F&&, Self&&, std::true_type /* void */) const {
171  return G<F, Self>();
172  }
173 
174  template<typename F, typename Self>
175  constexpr auto valued(F&&, Self&& self, std::false_type /* void */) const {
176  return G<F, Self>(in_place, *std::forward<Self>(self));
177  }
178 
179  public:
180  template<typename F, typename Self, std::enable_if_t<conjunction<
181  expected_error_invocable<F, Self>,
182  is_specialization<G<F, Self>, Expected>,
183  std::is_same<typename G<F, Self>::value_type, T>
184  >::value, int> = 0>
185  constexpr auto operator()(F&& f, Self&& self) const {
186  if (self.has_value()) {
187  return valued(std::forward<F>(f), std::forward<Self>(self), std::is_void<T>{});
188  } else {
189  return vccc::invoke(std::forward<F>(f), std::forward<Self>(self).error());
190  }
191  }
192 };
193 
194 template<typename Expected>
195 class expected_transform_error_t;
196 
197 template<template<typename, typename> class Expected, typename T, typename E>
198 class expected_transform_error_t<Expected<T, E>> {
199  template<typename F, typename Self>
200  using G = std::remove_cv_t<expected_error_invoke_result_t<F, Self>>;
201 
202  template<typename F, typename Self>
203  constexpr auto valued(F&&, Self&&, std::true_type) const {
204  return Expected<T, G<F, Self>>();
205  }
206 
207  template<typename F, typename Self>
208  constexpr auto valued(F&&, Self&& e, std::false_type) const {
209  return Expected<T, G<F, Self>>(in_place, *std::forward<Self>(e));
210  }
211 
212  public:
213  template<typename F, typename Self, std::enable_if_t<conjunction<
214  expected_error_invocable<F, Self>,
215  expected_valid_error_type<G<F, Self>>,
216  std::is_constructible<G<F, Self>, expected_error_invoke_result_t<F, Self>>
217  >::value, int> = 0>
218  constexpr auto operator()(F&& f, Self&& self) const {
219  if (self.has_value()) {
220  return valued(std::forward<F>(f), std::forward<Self>(self), std::is_void<T>{});
221  } else {
222  return Expected<T, G<F, Self>>(unexpect, vccc::invoke(std::forward<F>(f), std::forward<Self>(self).error()));
223  }
224  }
225 };
226 
227 } // namespace detail
228 } // namespace vccc
229 
230 #endif // VCCC_EXPECTED_MONADIC_HPP_
constexpr VCCC_INLINE_OR_STATIC unexpect_t unexpect
Definition: unexpect.hpp:34
constexpr invoke_result_t< F, Args... > invoke(F &&f, Args &&... args) noexcept(is_nothrow_invocable< F, Args... >::value)
Definition: invoke.hpp:38
constexpr T e
the mathematical constant
Definition: constants.hpp:37
void void_t
Definition: void_t.hpp:19
constexpr VCCC_INLINE_OR_STATIC in_place_t in_place
Definition: in_place.hpp:47
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35