Home | History | Annotate | Download | only in operators
      1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
      2 
      3 #pragma once
      4 
      5 /*! \file rx-any.hpp
      6 
      7     \brief Returns an Observable that emits true if any item emitted by the source Observable satisfies a specified condition, otherwise false. Emits false if the source Observable terminates without emitting any item.
      8 
      9     \tparam Predicate the type of the test function.
     10 
     11     \param p the test function to test items emitted by the source Observable.
     12 
     13     \return  An observable that emits true if any item emitted by the source observable satisfies a specified condition, otherwise false.
     14 
     15     Some basic any- operators have already been implemented:
     16     - rxcpp::operators::exists
     17     - rxcpp::operators::contains
     18 
     19     \sample
     20     \snippet exists.cpp exists sample
     21     \snippet output.txt exists sample
     22 
     23     \sample
     24     \snippet contains.cpp contains sample
     25     \snippet output.txt contains sample
     26 */
     27 
     28 
     29 #if !defined(RXCPP_OPERATORS_RX_ANY_HPP)
     30 #define RXCPP_OPERATORS_RX_ANY_HPP
     31 
     32 #include "../rx-includes.hpp"
     33 
     34 namespace rxcpp {
     35 
     36 namespace operators {
     37 
     38 namespace detail {
     39 
     40 template<class... AN>
     41 struct any_invalid_arguments {};
     42 
     43 template<class... AN>
     44 struct any_invalid : public rxo::operator_base<any_invalid_arguments<AN...>> {
     45     using type = observable<any_invalid_arguments<AN...>, any_invalid<AN...>>;
     46 };
     47 template<class... AN>
     48 using any_invalid_t = typename any_invalid<AN...>::type;
     49 
     50 template<class T, class Predicate>
     51 struct any
     52 {
     53     typedef rxu::decay_t<T> source_value_type;
     54     typedef bool value_type;
     55     typedef rxu::decay_t<Predicate> test_type;
     56     test_type test;
     57 
     58     any(test_type t)
     59         : test(std::move(t))
     60     {
     61     }
     62 
     63     template<class Subscriber>
     64     struct any_observer
     65     {
     66         typedef any_observer<Subscriber> this_type;
     67         typedef source_value_type value_type;
     68         typedef rxu::decay_t<Subscriber> dest_type;
     69         typedef observer<value_type, this_type> observer_type;
     70         dest_type dest;
     71         test_type test;
     72         mutable bool done;
     73 
     74         any_observer(dest_type d, test_type t)
     75             : dest(std::move(d))
     76             , test(std::move(t)),
     77               done(false)
     78         {
     79         }
     80         void on_next(source_value_type v) const {
     81             auto filtered = on_exception([&]() {
     82                 return !this->test(v); },
     83                 dest);
     84             if (filtered.empty()) {
     85                 return;
     86             }
     87             if (!filtered.get() && !done) {
     88                 done = true;
     89                 dest.on_next(true);
     90                 dest.on_completed();
     91             }
     92         }
     93         void on_error(rxu::error_ptr e) const {
     94             dest.on_error(e);
     95         }
     96         void on_completed() const {
     97             if(!done) {
     98                 done = true;
     99                 dest.on_next(false);
    100                 dest.on_completed();
    101             }
    102         }
    103 
    104         static subscriber<value_type, observer_type> make(dest_type d, test_type t) {
    105             return make_subscriber<value_type>(d, this_type(d, std::move(t)));
    106         }
    107     };
    108 
    109     template<class Subscriber>
    110     auto operator()(Subscriber dest) const
    111         -> decltype(any_observer<Subscriber>::make(std::move(dest), test)) {
    112         return      any_observer<Subscriber>::make(std::move(dest), test);
    113     }
    114 };
    115 
    116 }
    117 
    118 /*! @copydoc rx-any.hpp
    119 */
    120 template<class... AN>
    121 auto any(AN&&... an)
    122     ->     operator_factory<any_tag, AN...> {
    123     return operator_factory<any_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
    124 }
    125 
    126 /*! \brief Returns an Observable that emits true if any item emitted by the source Observable satisfies a specified condition, otherwise false. Emits false if the source Observable terminates without emitting any item.
    127 
    128     \tparam Predicate the type of the test function.
    129 
    130     \param p the test function to test items emitted by the source Observable.
    131 
    132     \return  An observable that emits true if any item emitted by the source observable satisfies a specified condition, otherwise false.
    133 
    134     \sample
    135     \snippet exists.cpp exists sample
    136     \snippet output.txt exists sample
    137 */
    138 template<class... AN>
    139 auto exists(AN&&... an)
    140     ->     operator_factory<exists_tag, AN...> {
    141     return operator_factory<exists_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
    142 }
    143 
    144 /*! \brief Returns an Observable that emits true if the source Observable emitted a specified item, otherwise false. Emits false if the source Observable terminates without emitting any item.
    145 
    146     \tparam T the type of the item to search for.
    147 
    148     \param value the item to search for.
    149 
    150     \return An observable that emits true if the source Observable emitted a specified item, otherwise false.
    151 
    152     \sample
    153     \snippet contains.cpp contains sample
    154     \snippet output.txt contains sample
    155 */
    156 template<class... AN>
    157 auto contains(AN&&... an)
    158 ->     operator_factory<contains_tag, AN...> {
    159     return operator_factory<contains_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
    160 }
    161 
    162 }
    163 
    164 template<>
    165 struct member_overload<any_tag>
    166 {
    167     template<class Observable, class Predicate,
    168         class SourceValue = rxu::value_type_t<Observable>,
    169         class Enabled = rxu::enable_if_all_true_type_t<
    170             is_observable<Observable>>,
    171         class Any = rxo::detail::any<SourceValue, rxu::decay_t<Predicate>>,
    172         class Value = rxu::value_type_t<Any>>
    173     static auto member(Observable&& o, Predicate&& p)
    174     -> decltype(o.template lift<Value>(Any(std::forward<Predicate>(p)))) {
    175         return  o.template lift<Value>(Any(std::forward<Predicate>(p)));
    176     }
    177 
    178     template<class... AN>
    179     static operators::detail::any_invalid_t<AN...> member(const AN&...) {
    180         std::terminate();
    181         return {};
    182         static_assert(sizeof...(AN) == 10000, "any takes (Predicate)");
    183     }
    184 };
    185 
    186 template<>
    187 struct member_overload<exists_tag>
    188     : member_overload<any_tag>
    189 {
    190     using member_overload<any_tag>::member;
    191 
    192     template<class... AN>
    193     static operators::detail::any_invalid_t<AN...> member(const AN&...) {
    194         std::terminate();
    195         return {};
    196         static_assert(sizeof...(AN) == 10000, "exists takes (Predicate)");
    197     }
    198 };
    199 
    200 template<>
    201 struct member_overload<contains_tag>
    202 {
    203     template<class Observable, class T,
    204         class SourceValue = rxu::value_type_t<Observable>,
    205         class Enabled = rxu::enable_if_all_true_type_t<
    206             is_observable<Observable>>,
    207         class Predicate = std::function<bool(T)>,
    208         class Any = rxo::detail::any<SourceValue, rxu::decay_t<Predicate>>,
    209         class Value = rxu::value_type_t<Any>>
    210     static auto member(Observable&& o, T&& value)
    211     -> decltype(o.template lift<Value>(Any(nullptr))) {
    212         return  o.template lift<Value>(Any([value](T n) { return n == value; }));
    213     }
    214 
    215     template<class... AN>
    216     static operators::detail::any_invalid_t<AN...> member(const AN&...) {
    217         std::terminate();
    218         return {};
    219         static_assert(sizeof...(AN) == 10000, "contains takes (T)");
    220     }
    221 };
    222 
    223 }
    224 
    225 #endif
    226