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