From fa9428c65f09f76024f0f2acfb819f22f0875320 Mon Sep 17 00:00:00 2001 From: Grigoriy Chudnov Date: Sat, 17 Dec 2016 21:39:39 +0300 Subject: decouple sequence_equal from observable (#295) * decouple sequence_equal from observable * refactoring to fix msvc2013 --- Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp | 141 ++++++++++++++++-------- Rx/v2/src/rxcpp/rx-includes.hpp | 1 + Rx/v2/src/rxcpp/rx-observable.hpp | 106 ++---------------- Rx/v2/src/rxcpp/rx-operators.hpp | 8 +- Rx/v2/src/rxcpp/rx-util.hpp | 11 ++ Rx/v2/test/operators/sequence_equal.cpp | 5 +- 6 files changed, 125 insertions(+), 147 deletions(-) (limited to 'Rx/v2') diff --git a/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp b/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp index 32a0d30..06253b4 100644 --- a/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp @@ -2,6 +2,25 @@ #pragma once +/*! \file rx-sequence_equal.hpp + + \brief Determine whether two Observables emit the same sequence of items. + + \tparam OtherSource the type of the other observable. + \tparam BinaryPredicate the type of the value comparing function (optional). The signature should be equivalent to the following: bool pred(const T1& a, const T2& b); + \tparam Coordination the type of the scheduler (optional). + + \param t the other Observable that emits items to compare. + \param pred the function that implements comparison of two values (optional). + \param cn the scheduler (optional). + + \return Observable that emits true only if both sequences terminate normally after emitting the same sequence of items in the same order; otherwise it will emit false. + + \sample + \snippet sequence_equal.cpp sequence_equal sample + \snippet output.txt sequence_equal sample +*/ + #if !defined(RXCPP_OPERATORS_RX_SEQUENCE_EQUAL_HPP) #define RXCPP_OPERATORS_RX_SEQUENCE_EQUAL_HPP @@ -13,6 +32,16 @@ namespace operators { namespace detail { +template +struct sequence_equal_invalid_arguments {}; + +template +struct sequence_equal_invalid : public rxo::operator_base> { + using type = observable, sequence_equal_invalid>; +}; +template +using sequence_equal_invalid_t = typename sequence_equal_invalid::type; + template struct sequence_equal : public operator_base { @@ -173,60 +202,80 @@ struct sequence_equal : public operator_base } }; -template -class sequence_equal_factory -{ - typedef rxu::decay_t other_source_type; - typedef rxu::decay_t coordination_type; - typedef rxu::decay_t predicate_type; - - other_source_type other_source; - coordination_type coordination; - predicate_type pred; - -public: - sequence_equal_factory(other_source_type t, predicate_type p, coordination_type sf) - : other_source(std::move(t)) - , coordination(std::move(sf)) - , pred(std::move(p)) - { - } - - template - auto operator()(Observable&& source) - -> observable>, Observable, other_source_type, BinaryPredicate, Coordination>> { - return observable>, Observable, other_source_type, BinaryPredicate, Coordination>>( - sequence_equal>, Observable, other_source_type, BinaryPredicate, Coordination>(std::forward(source), other_source, pred, coordination)); - } -}; - } -template -inline auto sequence_equal(OtherObservable&& t) - -> detail::sequence_equal_factory, identity_one_worker> { - return detail::sequence_equal_factory, identity_one_worker>(std::forward(t), rxu::equal_to<>(), identity_current_thread()); +/*! @copydoc rx-sequence_equal.hpp +*/ +template +auto sequence_equal(AN&&... an) + -> operator_factory { + return operator_factory(std::make_tuple(std::forward(an)...)); } -template::value>::type> -inline auto sequence_equal(OtherObservable&& t, BinaryPredicate&& pred) - -> detail::sequence_equal_factory { - return detail::sequence_equal_factory(std::forward(t), std::forward(pred), identity_current_thread()); } -template::value>::type> -inline auto sequence_equal(OtherObservable&& t, Coordination&& cn) - -> detail::sequence_equal_factory, Coordination> { - return detail::sequence_equal_factory, Coordination>(std::forward(t), rxu::equal_to<>(), std::forward(cn)); -} +template<> +struct member_overload +{ + template, + is_observable>, + class SourceValue = rxu::value_type_t, + class SequenceEqual = rxo::detail::sequence_equal, rxu::decay_t, rxu::equal_to<>, identity_one_worker>, + class Value = rxu::value_type_t, + class Result = observable> + static Result member(Observable&& o, OtherObservable&& t) { + return Result(SequenceEqual(std::forward(o), std::forward(t), rxu::equal_to<>(), identity_current_thread())); + } -template -inline auto sequence_equal(OtherObservable&& t, BinaryPredicate&& pred, Coordination&& cn) - -> detail::sequence_equal_factory { - return detail::sequence_equal_factory(std::forward(t), std::forward(pred), std::forward(cn)); -} + template, + class Enabled = rxu::enable_if_all_true_type_t< + is_observable, + is_observable, + rxu::negation>, + class SourceValue = rxu::value_type_t, + class SequenceEqual = rxo::detail::sequence_equal, rxu::decay_t, rxu::decay_t, identity_one_worker>, + class Value = rxu::value_type_t, + class Result = observable> + static Result member(Observable&& o, OtherObservable&& t, BinaryPredicate&& pred) { + return Result(SequenceEqual(std::forward(o), std::forward(t), std::forward(pred), identity_current_thread())); + } -} + template, + is_observable, + is_coordination>, + class SourceValue = rxu::value_type_t, + class SequenceEqual = rxo::detail::sequence_equal, rxu::decay_t, rxu::equal_to<>, rxu::decay_t>, + class Value = rxu::value_type_t, + class Result = observable> + static Result member(Observable&& o, OtherObservable&& t, Coordination&& cn) { + return Result(SequenceEqual(std::forward(o), std::forward(t), rxu::equal_to<>(), std::forward(cn))); + } + + template, + is_observable, + is_coordination>, + class SourceValue = rxu::value_type_t, + class SequenceEqual = rxo::detail::sequence_equal, rxu::decay_t, rxu::decay_t, rxu::decay_t>, + class Value = rxu::value_type_t, + class Result = observable> + static Result member(Observable&& o, OtherObservable&& t, BinaryPredicate&& pred, Coordination&& cn) { + return Result(SequenceEqual(std::forward(o), std::forward(t), std::forward(pred), std::forward(cn))); + } + + template + static operators::detail::sequence_equal_invalid_t member(const AN&...) { + std::terminate(); + return {}; + static_assert(sizeof...(AN) == 10000, "sequence_equal takes (OtherObservable, optional BinaryPredicate, optional Coordination)"); + } +}; } diff --git a/Rx/v2/src/rxcpp/rx-includes.hpp b/Rx/v2/src/rxcpp/rx-includes.hpp index 2feec7d..283793e 100644 --- a/Rx/v2/src/rxcpp/rx-includes.hpp +++ b/Rx/v2/src/rxcpp/rx-includes.hpp @@ -197,6 +197,7 @@ #include "operators/rx-map.hpp" #include "operators/rx-on_error_resume_next.hpp" #include "operators/rx-reduce.hpp" +#include "operators/rx-sequence_equal.hpp" #include "operators/rx-take_while.hpp" #include "operators/rx-retry.hpp" #include "operators/rx-with_latest_from.hpp" diff --git a/Rx/v2/src/rxcpp/rx-observable.hpp b/Rx/v2/src/rxcpp/rx-observable.hpp index 2ff85ae..ff68936 100644 --- a/Rx/v2/src/rxcpp/rx-observable.hpp +++ b/Rx/v2/src/rxcpp/rx-observable.hpp @@ -838,105 +838,15 @@ public: return switch_if_empty(rxs::from(std::move(v))); } - /*! Determine whether two Observables emit the same sequence of items. - - \tparam OtherSource the type of the other observable. - \tparam BinaryPredicate the type of the value comparing function. The signature should be equivalent to the following: bool pred(const T1& a, const T2& b); - \tparam Coordination the type of the scheduler. - - \param t the other Observable that emits items to compare. - \param pred the function that implements comparison of two values. - \param cn the scheduler. - - \return Observable that emits true only if both sequences terminate normally after emitting the same sequence of items in the same order; otherwise it will emit false. - - \sample - \snippet sequence_equal.cpp sequence_equal sample - \snippet output.txt sequence_equal sample - */ - template - auto sequence_equal(OtherSource&& t, BinaryPredicate&& pred, Coordination&& cn) const - /// \cond SHOW_SERVICE_MEMBERS - -> typename std::enable_if::value, - observable>>::type - /// \endcond - { - return observable>( - rxo::detail::sequence_equal(*this, std::forward(t), std::forward(pred), std::forward(cn))); - } - - - /*! Determine whether two Observables emit the same sequence of items. - - \tparam OtherSource the type of the other observable. - \tparam BinaryPredicate the type of the value comparing function. The signature should be equivalent to the following: bool pred(const T1& a, const T2& b); - - \param t the other Observable that emits items to compare. - \param pred the function that implements comparison of two values. - - \return Observable that emits true only if both sequences terminate normally after emitting the same sequence of items in the same order; otherwise it will emit false. - - \sample - \snippet sequence_equal.cpp sequence_equal sample - \snippet output.txt sequence_equal sample - */ - template - auto sequence_equal(OtherSource&& t, BinaryPredicate&& pred) const - /// \cond SHOW_SERVICE_MEMBERS - -> typename std::enable_if::value && !is_coordination::value, - observable>>::type - /// \endcond - { - return observable>( - rxo::detail::sequence_equal(*this, std::forward(t), std::forward(pred), identity_one_worker(rxsc::make_current_thread()))); - } - - /*! Determine whether two Observables emit the same sequence of items. - - \tparam OtherSource the type of the other observable. - \tparam Coordination the type of the scheduler. - - \param t the other Observable that emits items to compare. - \param cn the scheduler. - - \return Observable that emits true only if both sequences terminate normally after emitting the same sequence of items in the same order; otherwise it will emit false. - - \sample - \snippet sequence_equal.cpp sequence_equal sample - \snippet output.txt sequence_equal sample - */ - template - auto sequence_equal(OtherSource&& t, Coordination&& cn) const - /// \cond SHOW_SERVICE_MEMBERS - -> typename std::enable_if::value && is_coordination::value, - observable, Coordination>>>::type - /// \endcond - { - return observable, Coordination>>( - rxo::detail::sequence_equal, Coordination>(*this, std::forward(t), rxu::equal_to<>(), std::forward(cn))); - } - - /*! Determine whether two Observables emit the same sequence of items. - - \tparam OtherSource the type of the other observable. - - \param t the other Observable that emits items to compare. - - \return Observable that emits true only if both sequences terminate normally after emitting the same sequence of items in the same order; otherwise it will emit false. - - \sample - \snippet sequence_equal.cpp sequence_equal sample - \snippet output.txt sequence_equal sample - */ - template - auto sequence_equal(OtherSource&& t) const - /// \cond SHOW_SERVICE_MEMBERS - -> typename std::enable_if::value, - observable, identity_one_worker>>>::type - /// \endcond + /*! @copydoc rx-sequence_equal.hpp + */ + template + auto sequence_equal(AN... an) const + /// \cond SHOW_SERVICE_MEMBERS + -> decltype(observable_member(sequence_equal_tag{}, *(this_type*)nullptr, std::forward(an)...)) + /// \endcond { - return observable, identity_one_worker>>( - rxo::detail::sequence_equal, identity_one_worker>(*this, std::forward(t), rxu::equal_to<>(), identity_one_worker(rxsc::make_current_thread()))); + return observable_member(sequence_equal_tag{}, *this, std::forward(an)...); } /*! inspect calls to on_next, on_error and on_completed. diff --git a/Rx/v2/src/rxcpp/rx-operators.hpp b/Rx/v2/src/rxcpp/rx-operators.hpp index be4d485..975c4e6 100644 --- a/Rx/v2/src/rxcpp/rx-operators.hpp +++ b/Rx/v2/src/rxcpp/rx-operators.hpp @@ -114,7 +114,6 @@ public: #include "operators/rx-replay.hpp" #include "operators/rx-sample_time.hpp" #include "operators/rx-scan.hpp" -#include "operators/rx-sequence_equal.hpp" #include "operators/rx-skip.hpp" #include "operators/rx-skip_last.hpp" #include "operators/rx-skip_until.hpp" @@ -274,6 +273,13 @@ struct retry_tag { }; }; +struct sequence_equal_tag { + template + struct include_header{ + static_assert(Included::value, "missing include: please #include "); + }; +}; + struct with_latest_from_tag { template struct include_header{ diff --git a/Rx/v2/src/rxcpp/rx-util.hpp b/Rx/v2/src/rxcpp/rx-util.hpp index 3ddc0b9..0e09301 100644 --- a/Rx/v2/src/rxcpp/rx-util.hpp +++ b/Rx/v2/src/rxcpp/rx-util.hpp @@ -780,6 +780,17 @@ namespace detail { template > struct is_duration : detail::is_duration {}; + +// C++17 negation +namespace detail { + template + struct not_value : std::conditional::type { + }; +} + +template +struct negation : detail::not_value {}; + } namespace rxu=util; diff --git a/Rx/v2/test/operators/sequence_equal.cpp b/Rx/v2/test/operators/sequence_equal.cpp index b1b5046..6ada320 100644 --- a/Rx/v2/test/operators/sequence_equal.cpp +++ b/Rx/v2/test/operators/sequence_equal.cpp @@ -1,4 +1,5 @@ #include "../test.h" +#include "rxcpp/operators/rx-sequence_equal.hpp" SCENARIO("sequence_equal - source never emits", "[sequence_equal][operators]"){ GIVEN("two sources"){ @@ -24,8 +25,8 @@ SCENARIO("sequence_equal - source never emits", "[sequence_equal][operators]"){ auto res = w.start( [xs, ys]() { return xs - .sequence_equal(ys) - .as_dynamic(); // forget type to workaround lambda deduction bug on msvc 2013 + | rxo::sequence_equal(ys) + | rxo::as_dynamic(); // forget type to workaround lambda deduction bug on msvc 2013 } ); -- cgit v1.2.3