diff options
author | Grigoriy Chudnov <g.chudnov@gmail.com> | 2017-01-16 20:30:12 +0300 |
---|---|---|
committer | Kirk Shoop <kirk.shoop@microsoft.com> | 2017-01-16 09:30:12 -0800 |
commit | 6a35d221de3054885b69f1c82a78c99c83a8f47a (patch) | |
tree | 371a3c42d09066494a4e96b78e1cbd6fffd16a65 | |
parent | 7923baae257f7036eea164d30055756e88cea498 (diff) | |
download | RxCpp-6a35d221de3054885b69f1c82a78c99c83a8f47a.tar.gz |
decouple switch_if_empty, default_if_empty from observable (#329)
* decouple switch_if_empty, default_if_empty from observable
* decouple switch_if_empty, default_if_empty from observable - fix compile errors
* decouple switch_if_empty, default_if_empty from observable - fix ref
* decouple switch_if_empty, default_if_empty from observable - fix msvc2013
-rw-r--r-- | Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp | 108 | ||||
-rw-r--r-- | Rx/v2/src/rxcpp/rx-includes.hpp | 1 | ||||
-rw-r--r-- | Rx/v2/src/rxcpp/rx-observable.hpp | 47 | ||||
-rw-r--r-- | Rx/v2/src/rxcpp/rx-operators.hpp | 9 | ||||
-rw-r--r-- | Rx/v2/test/operators/default_if_empty.cpp | 21 | ||||
-rw-r--r-- | Rx/v2/test/operators/switch_if_empty.cpp | 26 |
6 files changed, 152 insertions, 60 deletions
diff --git a/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp b/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp index cf51109..b9bab52 100644 --- a/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp @@ -2,6 +2,21 @@ #pragma once +/*! \file rx-switch_if_empty.hpp + + \brief If the source Observable terminates without emitting any items, emits items from a backup Observable. + + \tparam BackupSource the type of the backup observable. + + \param t a backup observable that is used if the source observable is empty. + + \return Observable that emits items from a backup observable if the source observable is empty. + + \sample + \snippet switch_if_empty.cpp switch_if_empty sample + \snippet output.txt switch_if_empty sample +*/ + #if !defined(RXCPP_OPERATORS_RX_SWITCH_IF_EMPTY_HPP) #define RXCPP_OPERATORS_RX_SWITCH_IF_EMPTY_HPP @@ -13,6 +28,16 @@ namespace operators { namespace detail { +template<class... AN> +struct switch_if_empty_invalid_arguments {}; + +template<class... AN> +struct switch_if_empty_invalid : public rxo::operator_base<switch_if_empty_invalid_arguments<AN...>> { + using type = observable<switch_if_empty_invalid_arguments<AN...>, switch_if_empty_invalid<AN...>>; +}; +template<class... AN> +using switch_if_empty_invalid_t = typename switch_if_empty_invalid<AN...>::type; + template<class T, class BackupSource> struct switch_if_empty { @@ -75,30 +100,79 @@ struct switch_if_empty } }; -template<class BackupSource> -class switch_if_empty_factory -{ - typedef rxu::decay_t<BackupSource> backup_source_type; - backup_source_type backup; -public: - switch_if_empty_factory(backup_source_type b) : backup(std::move(b)) {} - template<class Observable> - auto operator()(Observable&& source) - -> decltype(source.template lift<rxu::value_type_t<rxu::decay_t<Observable>>>(switch_if_empty<rxu::value_type_t<rxu::decay_t<Observable>>, backup_source_type>(backup))) { - return source.template lift<rxu::value_type_t<rxu::decay_t<Observable>>>(switch_if_empty<rxu::value_type_t<rxu::decay_t<Observable>>, backup_source_type>(backup)); - } -}; +} +/*! @copydoc rx-switch_if_empty.hpp +*/ +template<class... AN> +auto switch_if_empty(AN&&... an) + -> operator_factory<switch_if_empty_tag, AN...> { + return operator_factory<switch_if_empty_tag, AN...>(std::make_tuple(std::forward<AN>(an)...)); } -template<class BackupSource> -auto switch_if_empty(BackupSource&& b) - -> detail::switch_if_empty_factory<BackupSource> { - return detail::switch_if_empty_factory<BackupSource>(std::forward<BackupSource>(b)); +/*! \brief If the source Observable terminates without emitting any items, emits a default item and completes. + + \tparam Value the type of the value to emit. + + \param v the default value to emit. + + \return Observable that emits the specified default item if the source observable is empty. + + \sample + \snippet default_if_empty.cpp default_if_empty sample + \snippet output.txt default_if_empty sample +*/ +template<class... AN> +auto default_if_empty(AN&&... an) + -> operator_factory<default_if_empty_tag, AN...> { + return operator_factory<default_if_empty_tag, AN...>(std::make_tuple(std::forward<AN>(an)...)); } } +template<> +struct member_overload<switch_if_empty_tag> +{ + template<class Observable, class BackupSource, + class Enabled = rxu::enable_if_all_true_type_t< + all_observables<Observable, BackupSource>>, + class SourceValue = rxu::value_type_t<Observable>, + class SwitchIfEmpty = rxo::detail::switch_if_empty<SourceValue, rxu::decay_t<BackupSource>>> + static auto member(Observable&& o, BackupSource&& b) + -> decltype(o.template lift<SourceValue>(SwitchIfEmpty(std::forward<BackupSource>(b)))) { + return o.template lift<SourceValue>(SwitchIfEmpty(std::forward<BackupSource>(b))); + } + + template<class... AN> + static operators::detail::switch_if_empty_invalid_t<AN...> member(AN...) { + std::terminate(); + return {}; + static_assert(sizeof...(AN) == 10000, "switch_if_empty takes (BackupSource)"); + } +}; + +template<> +struct member_overload<default_if_empty_tag> +{ + template<class Observable, class Value, + class Enabled = rxu::enable_if_all_true_type_t< + is_observable<Observable>>, + class SourceValue = rxu::value_type_t<Observable>, + class BackupSource = decltype(rxs::from(std::declval<SourceValue>())), + class DefaultIfEmpty = rxo::detail::switch_if_empty<SourceValue, BackupSource>> + static auto member(Observable&& o, Value v) + -> decltype(o.template lift<SourceValue>(DefaultIfEmpty(rxs::from(std::move(v))))) { + return o.template lift<SourceValue>(DefaultIfEmpty(rxs::from(std::move(v)))); + } + + template<class... AN> + static operators::detail::switch_if_empty_invalid_t<AN...> member(AN...) { + std::terminate(); + return {}; + static_assert(sizeof...(AN) == 10000, "default_if_empty takes (Value)"); + } +}; + } #endif diff --git a/Rx/v2/src/rxcpp/rx-includes.hpp b/Rx/v2/src/rxcpp/rx-includes.hpp index 91a641f..3255fd9 100644 --- a/Rx/v2/src/rxcpp/rx-includes.hpp +++ b/Rx/v2/src/rxcpp/rx-includes.hpp @@ -212,6 +212,7 @@ #include "operators/rx-skip.hpp" #include "operators/rx-skip_last.hpp" #include "operators/rx-skip_until.hpp" +#include "operators/rx-switch_if_empty.hpp" #include "operators/rx-take.hpp" #include "operators/rx-take_last.hpp" #include "operators/rx-take_until.hpp" diff --git a/Rx/v2/src/rxcpp/rx-observable.hpp b/Rx/v2/src/rxcpp/rx-observable.hpp index 74c4218..89d3daa 100644 --- a/Rx/v2/src/rxcpp/rx-observable.hpp +++ b/Rx/v2/src/rxcpp/rx-observable.hpp @@ -797,45 +797,26 @@ public: return observable_member(filter_tag{}, *this, std::forward<AN>(an)...); } - /*! If the source Observable terminates without emitting any items, emits items from a backup Observable. - - \tparam BackupSource the type of the backup observable. - - \param t a backup observable that is used if the source observable is empty. - - \return Observable that emits items from a backup observable if the source observable is empty. - - \sample - \snippet switch_if_empty.cpp switch_if_empty sample - \snippet output.txt switch_if_empty sample + /*! @copydoc rx-switch_if_empty.hpp */ - template<class BackupSource> - auto switch_if_empty(BackupSource t) const - /// \cond SHOW_SERVICE_MEMBERS - -> typename std::enable_if<is_observable<BackupSource>::value, - decltype(EXPLICIT_THIS lift<T>(rxo::detail::switch_if_empty<T, BackupSource>(std::move(t))))>::type - /// \endcond + template<class... AN> + auto switch_if_empty(AN&&... an) const + /// \cond SHOW_SERVICE_MEMBERS + -> decltype(observable_member(switch_if_empty_tag{}, *(this_type*)nullptr, std::forward<AN>(an)...)) + /// \endcond { - return lift<T>(rxo::detail::switch_if_empty<T, BackupSource>(std::move(t))); + return observable_member(switch_if_empty_tag{}, *this, std::forward<AN>(an)...); } - /*! If the source Observable terminates without emitting any items, emits a default item and completes. - - \tparam V the type of the value to emit. - - \param v the default value to emit - - \return Observable that emits the specified default item if the source observable is empty. - - \sample - \snippet default_if_empty.cpp default_if_empty sample - \snippet output.txt default_if_empty sample + /*! @copydoc rxcpp::operators::default_if_empty */ - template <typename V> - auto default_if_empty(V v) const - -> decltype(EXPLICIT_THIS switch_if_empty(rxs::from(std::move(v)))) + template<class... AN> + auto default_if_empty(AN&&... an) const + /// \cond SHOW_SERVICE_MEMBERS + -> decltype(observable_member(default_if_empty_tag{}, *(this_type*)nullptr, std::forward<AN>(an)...)) + /// \endcond { - return switch_if_empty(rxs::from(std::move(v))); + return observable_member(default_if_empty_tag{}, *this, std::forward<AN>(an)...); } /*! @copydoc rx-sequence_equal.hpp diff --git a/Rx/v2/src/rxcpp/rx-operators.hpp b/Rx/v2/src/rxcpp/rx-operators.hpp index 5bf6109..208b3ef 100644 --- a/Rx/v2/src/rxcpp/rx-operators.hpp +++ b/Rx/v2/src/rxcpp/rx-operators.hpp @@ -107,7 +107,6 @@ public: #include "operators/rx-start_with.hpp" #include "operators/rx-subscribe.hpp" #include "operators/rx-subscribe_on.hpp" -#include "operators/rx-switch_if_empty.hpp" #include "operators/rx-switch_on_next.hpp" namespace rxcpp { @@ -340,6 +339,14 @@ struct skip_until_tag { }; }; +struct switch_if_empty_tag { + template<class Included> + struct include_header{ + static_assert(Included::value, "missing include: please #include <rxcpp/operators/rx-switch_if_empty.hpp>"); + }; +}; +struct default_if_empty_tag : switch_if_empty_tag {}; + struct take_tag { template<class Included> struct include_header{ diff --git a/Rx/v2/test/operators/default_if_empty.cpp b/Rx/v2/test/operators/default_if_empty.cpp index 048c8d5..3acd73a 100644 --- a/Rx/v2/test/operators/default_if_empty.cpp +++ b/Rx/v2/test/operators/default_if_empty.cpp @@ -1,4 +1,5 @@ #include "../test.h" +#include <rxcpp/operators/rx-switch_if_empty.hpp> SCENARIO("default_if_empty should not switch if the source is not empty", "[default_if_empty][operators]"){ GIVEN("a source"){ @@ -15,7 +16,10 @@ SCENARIO("default_if_empty should not switch if the source is not empty", "[defa auto res = w.start( [xs]() { - return xs.default_if_empty(2); + return xs + | rxo::default_if_empty(2) + // forget type to workaround lambda deduction bug on msvc 2013 + | rxo::as_dynamic(); } ); @@ -54,7 +58,10 @@ SCENARIO("default_if_empty should switch if the source is empty", "[default_if_e auto res = w.start( [xs]() { - return xs.default_if_empty(2); + return xs + .default_if_empty(2) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); @@ -92,7 +99,10 @@ SCENARIO("default_if_empty - never", "[default_if_empty][operators]"){ auto res = w.start( [xs]() { - return xs.default_if_empty(2); + return xs + .default_if_empty(2) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); @@ -130,7 +140,10 @@ SCENARIO("default_if_empty - source throws", "[default_if_empty][operators]"){ auto res = w.start( [xs]() { - return xs.default_if_empty(2); + return xs + .default_if_empty(2) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); diff --git a/Rx/v2/test/operators/switch_if_empty.cpp b/Rx/v2/test/operators/switch_if_empty.cpp index 779087e..b205858 100644 --- a/Rx/v2/test/operators/switch_if_empty.cpp +++ b/Rx/v2/test/operators/switch_if_empty.cpp @@ -1,4 +1,5 @@ #include "../test.h" +#include <rxcpp/operators/rx-switch_if_empty.hpp> SCENARIO("switch_if_empty should not switch if the source is not empty", "[switch_if_empty][operators]"){ GIVEN("a source"){ @@ -20,7 +21,10 @@ SCENARIO("switch_if_empty should not switch if the source is not empty", "[switc auto res = w.start( [xs, ys]() { - return xs.switch_if_empty(ys); + return xs + | rxo::switch_if_empty(ys) + // forget type to workaround lambda deduction bug on msvc 2013 + | rxo::as_dynamic(); } ); @@ -70,7 +74,10 @@ SCENARIO("switch_if_empty should switch if the source is empty", "[switch_if_emp auto res = w.start( [xs, ys]() { - return xs.switch_if_empty(ys); + return xs + .switch_if_empty(ys) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); @@ -121,7 +128,10 @@ SCENARIO("switch_if_empty - never", "[switch_if_empty][operators]"){ auto res = w.start( [xs, ys]() { - return xs.switch_if_empty(ys); + return xs + .switch_if_empty(ys) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); @@ -170,7 +180,10 @@ SCENARIO("switch_if_empty - source throws", "[switch_if_empty][operators]"){ auto res = w.start( [xs, ys]() { - return xs.switch_if_empty(ys); + return xs + .switch_if_empty(ys) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); @@ -220,7 +233,10 @@ SCENARIO("switch_if_empty - backup source throws", "[switch_if_empty][operators] auto res = w.start( [xs, ys]() { - return xs.switch_if_empty(ys); + return xs + .switch_if_empty(ys) + // forget type to workaround lambda deduction bug on msvc 2013 + .as_dynamic(); } ); |