summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrigoriy Chudnov <g.chudnov@gmail.com>2017-01-16 20:30:12 +0300
committerKirk Shoop <kirk.shoop@microsoft.com>2017-01-16 09:30:12 -0800
commit6a35d221de3054885b69f1c82a78c99c83a8f47a (patch)
tree371a3c42d09066494a4e96b78e1cbd6fffd16a65
parent7923baae257f7036eea164d30055756e88cea498 (diff)
downloadRxCpp-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.hpp108
-rw-r--r--Rx/v2/src/rxcpp/rx-includes.hpp1
-rw-r--r--Rx/v2/src/rxcpp/rx-observable.hpp47
-rw-r--r--Rx/v2/src/rxcpp/rx-operators.hpp9
-rw-r--r--Rx/v2/test/operators/default_if_empty.cpp21
-rw-r--r--Rx/v2/test/operators/switch_if_empty.cpp26
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();
}
);