Commit b69b3f90 authored by Dominik Charousset's avatar Dominik Charousset

Implement new flat_map variant for optional values

parent 42340cf9
...@@ -203,6 +203,11 @@ public: ...@@ -203,6 +203,11 @@ public:
template <class F> template <class F>
auto flat_map(F f); auto flat_map(F f);
/// Returns a transformation that emits items from optional values returned by
/// `f`.
template <class F>
transformation<flat_map_optional_step<F>> flat_map_optional(F f);
/// Returns a transformation that emits items by concatenating the outputs of /// Returns a transformation that emits items by concatenating the outputs of
/// all observables returned by `f`. /// all observables returned by `f`.
template <class F> template <class F>
...@@ -1012,6 +1017,11 @@ public: ...@@ -1012,6 +1017,11 @@ public:
return std::move(*this).transform(map_step<F>{std::move(f)}); return std::move(*this).transform(map_step<F>{std::move(f)});
} }
template <class F>
auto flat_map_optional(F f) && {
return std::move(*this).transform(flat_map_optional_step<F>{std::move(f)});
}
template <class F> template <class F>
auto do_on_complete(F f) && { auto do_on_complete(F f) && {
return std::move(*this) // return std::move(*this) //
...@@ -1049,7 +1059,7 @@ template <class T> ...@@ -1049,7 +1059,7 @@ template <class T>
template <class Step> template <class Step>
transformation<Step> observable<T>::transform(Step step) { transformation<Step> observable<T>::transform(Step step) {
static_assert(std::is_same_v<typename Step::input_type, T>, static_assert(std::is_same_v<typename Step::input_type, T>,
"step object does not match the output type"); "step object does not match the input type");
return {*this, std::forward_as_tuple(std::move(step))}; return {*this, std::forward_as_tuple(std::move(step))};
} }
...@@ -1068,7 +1078,7 @@ transformation<filter_step<Predicate>> ...@@ -1068,7 +1078,7 @@ transformation<filter_step<Predicate>>
observable<T>::filter(Predicate predicate) { observable<T>::filter(Predicate predicate) {
using step_type = filter_step<Predicate>; using step_type = filter_step<Predicate>;
static_assert(std::is_same_v<typename step_type::input_type, T>, static_assert(std::is_same_v<typename step_type::input_type, T>,
"predicate does not match the output type"); "predicate does not match the input type");
return {*this, std::forward_as_tuple(step_type{std::move(predicate)})}; return {*this, std::forward_as_tuple(step_type{std::move(predicate)})};
} }
...@@ -1079,7 +1089,7 @@ template <class F> ...@@ -1079,7 +1089,7 @@ template <class F>
transformation<map_step<F>> observable<T>::map(F f) { transformation<map_step<F>> observable<T>::map(F f) {
using step_type = map_step<F>; using step_type = map_step<F>;
static_assert(std::is_same_v<typename step_type::input_type, T>, static_assert(std::is_same_v<typename step_type::input_type, T>,
"map function does not match the output type"); "map function does not match the input type");
return {*this, std::forward_as_tuple(step_type{std::move(f)})}; return {*this, std::forward_as_tuple(step_type{std::move(f)})};
} }
...@@ -1474,6 +1484,18 @@ auto observable<T>::flat_map(F f) { ...@@ -1474,6 +1484,18 @@ auto observable<T>::flat_map(F f) {
return obs->merger(); return obs->merger();
} }
// -- observable::flat_map_optional --------------------------------------------
template <class T>
template <class F>
transformation<flat_map_optional_step<F>>
observable<T>::flat_map_optional(F f) {
using step_type = flat_map_optional_step<F>;
static_assert(std::is_same_v<typename step_type::input_type, T>,
"flat_map_optional function does not match the input type");
return {*this, std::forward_as_tuple(step_type{std::move(f)})};
}
// -- observable::concat_map --------------------------------------------------- // -- observable::concat_map ---------------------------------------------------
template <class T> template <class T>
......
...@@ -201,6 +201,11 @@ public: ...@@ -201,6 +201,11 @@ public:
return std::move(*this).transform(map_step<Fn>{std::move(fn)}); return std::move(*this).transform(map_step<Fn>{std::move(fn)});
} }
template <class F>
auto flat_map_optional(F f) && {
return std::move(*this).transform(flat_map_optional_step<F>{std::move(f)});
}
observable<output_type> as_observable() && override { observable<output_type> as_observable() && override {
auto pimpl = make_counted<impl>(ctx_, std::move(gen_), std::move(steps_)); auto pimpl = make_counted<impl>(ctx_, std::move(gen_), std::move(steps_));
return observable<output_type>{std::move(pimpl)}; return observable<output_type>{std::move(pimpl)};
......
...@@ -112,6 +112,43 @@ struct map_step { ...@@ -112,6 +112,43 @@ struct map_step {
} }
}; };
template <class Fn>
struct flat_map_optional_step {
using trait = detail::get_callable_trait_t<Fn>;
static_assert(!std::is_same_v<typename trait::result_type, void>,
"flat_map_optional functions may not return void");
static_assert(trait::num_args == 1,
"flat_map_optional functions must take exactly one argument");
using input_type = std::decay_t<detail::tl_head_t<typename trait::arg_types>>;
using intermediate_type = std::decay_t<typename trait::result_type>;
using output_type = typename intermediate_type::value_type;
Fn fn;
template <class Next, class... Steps>
bool on_next(const input_type& item, Next& next, Steps&... steps) {
if (auto val = fn(item))
return next.on_next(*val, steps...);
else
return true;
}
template <class Next, class... Steps>
void on_complete(Next& next, Steps&... steps) {
next.on_complete(steps...);
}
template <class Next, class... Steps>
void on_error(const error& what, Next& next, Steps&... steps) {
next.on_error(what, steps...);
}
};
template <class T, class Fn> template <class T, class Fn>
struct on_complete_step { struct on_complete_step {
using input_type = T; using input_type = T;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment