6#ifndef GIMO_ALGORITHM_OR_ELSE_HPP
7#define GIMO_ALGORITHM_OR_ELSE_HPP
21namespace gimo::detail::or_else
23 template <
typename Nullable,
typename Action>
24 consteval Nullable& print_diagnostics()
26 if constexpr (!std::is_invocable_v<Action>)
28 static_assert(always_false_v<Nullable>,
"The or_else algorithm requires an action invocable without any arguments.");
30 else if constexpr (!std::same_as<Nullable, std::invoke_result_t<Action>> && !std::is_void_v<std::invoke_result_t<Action>>)
32 static_assert(always_false_v<Nullable>,
"The or_else algorithm requires an action returning the same nullable type or void.");
35 return std::declval<Nullable&>();
38 template <
typename Action, nullable Nullable>
40 constexpr std::remove_cvref_t<Nullable> on_value(Action&& , Nullable&& opt)
42 return std::forward<Nullable>(opt);
45 template <
typename Action, nullable Nullable,
typename Next,
typename... Steps>
47 constexpr auto on_value(
53 return std::forward<Next>(next).on_value(
54 std::forward<Nullable>(opt),
55 std::forward<Steps>(steps)...);
58 template <
typename Action, nullable Nullable>
60 constexpr std::remove_cvref_t<Nullable> on_null(Action&& action, Nullable&& )
62 if constexpr (std::is_void_v<std::invoke_result_t<Action>>)
64 std::invoke(std::forward<Action>(action));
65 return detail::construct_empty<std::remove_cvref_t<Nullable>>();
69 return std::invoke(std::forward<Action>(action));
73 template <nullable Nullable,
typename Action,
typename Next,
typename... Steps>
75 constexpr auto on_null(Action&& action, Nullable&& opt, Next&& next, Steps&&... steps)
78 std::forward<Next>(next),
79 or_else::on_null(std::forward<Action>(action), std::forward<Nullable>(opt)),
80 std::forward<Steps>(steps)...);
83 template <nullable Nullable,
typename Action,
typename Next,
typename... Steps>
84 requires std::is_void_v<std::invoke_result_t<Action>>
86 constexpr auto on_null(Action&& action, Nullable&& opt, Next&& next, Steps&&... steps)
88 return std::forward<Next>(next).on_null(
89 or_else::on_null(std::forward<Action>(action), std::forward<Nullable>(opt)),
90 std::forward<Steps>(steps)...);
95 template <nullable Nullable,
typename Action>
96 static constexpr bool is_applicable_on =
requires {
97 requires std::same_as<
98 std::remove_cvref_t<Nullable>,
99 std::remove_cvref_t<std::invoke_result_t<Action>>>
100 || std::is_void_v<std::invoke_result_t<Action>>;
103 template <
typename Action, nullable Nullable,
typename... Steps>
105 static constexpr auto on_value(Action&& action, Nullable&& opt, Steps&&... steps)
107 GIMO_ASSERT(detail::has_value(opt),
"Nullable is empty while it's expected to contain a value.");
109 if constexpr (is_applicable_on<Nullable, Action>)
111 return or_else::on_value(
112 std::forward<Action>(action),
113 std::forward<Nullable>(opt),
114 std::forward<Steps>(steps)...);
118 return or_else::print_diagnostics<Nullable, Action>();
122 template <
typename Action, nullable Nullable,
typename... Steps>
124 static constexpr auto on_null(Action&& action, Nullable&& opt, Steps&&... steps)
126 GIMO_ASSERT(!detail::has_value(opt),
"Nullable contains a value while it's expected to be empty.");
128 if constexpr (is_applicable_on<Nullable, Action>)
130 return or_else::on_null(
131 std::forward<Action>(action),
132 std::forward<Nullable>(opt),
133 std::forward<Steps>(steps)...);
137 return or_else::print_diagnostics<Nullable, Action>();
147 template <
typename Action>
148 using or_else_t = BasicAlgorithm<or_else::traits, std::remove_cvref_t<Action>>;
162 template <
typename Action>
166 using Algorithm = detail::or_else_t<Action>;
168 return Pipeline{std::tuple<Algorithm>{std::forward<Action>(action)}};
#define GIMO_ASSERT(condition, msg,...)
Definition Config.hpp:11
A composite object representing a sequence of monadic operations.
Definition Pipeline.hpp:30
constexpr auto or_else(Action &&action)
Creates a pipeline step that handles the null/error case.
Definition OrElse.hpp:164
Definition AndForward.hpp:21