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
anyrxcpp::operators::detail::any58 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
any_observerrxcpp::operators::detail::any::any_observer74 any_observer(dest_type d, test_type t)
75 : dest(std::move(d))
76 , test(std::move(t)),
77 done(false)
78 {
79 }
on_nextrxcpp::operators::detail::any::any_observer80 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 }
on_errorrxcpp::operators::detail::any::any_observer93 void on_error(rxu::error_ptr e) const {
94 dest.on_error(e);
95 }
on_completedrxcpp::operators::detail::any::any_observer96 void on_completed() const {
97 if(!done) {
98 done = true;
99 dest.on_next(false);
100 dest.on_completed();
101 }
102 }
103
makerxcpp::operators::detail::any::any_observer104 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>
operator ()rxcpp::operators::detail::any110 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>
any(AN &&...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>
exists(AN &&...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>
contains(AN &&...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>>
memberrxcpp::member_overload173 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>
memberrxcpp::member_overload179 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>
memberrxcpp::member_overload193 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>>
memberrxcpp::member_overload210 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>
memberrxcpp::member_overload216 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