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-map.hpp 6 7 \brief For each item from this observable use Selector to produce an item to emit from the new observable that is returned. 8 9 \tparam Selector the type of the transforming function 10 11 \param s the selector function 12 13 \return Observable that emits the items from the source observable, transformed by the specified function. 14 15 \sample 16 \snippet map.cpp map sample 17 \snippet output.txt map sample 18 */ 19 20 #if !defined(RXCPP_OPERATORS_RX_MAP_HPP) 21 #define RXCPP_OPERATORS_RX_MAP_HPP 22 23 #include "../rx-includes.hpp" 24 25 namespace rxcpp { 26 27 namespace operators { 28 29 namespace detail { 30 31 template<class... AN> 32 struct map_invalid_arguments {}; 33 34 template<class... AN> 35 struct map_invalid : public rxo::operator_base<map_invalid_arguments<AN...>> { 36 using type = observable<map_invalid_arguments<AN...>, map_invalid<AN...>>; 37 }; 38 template<class... AN> 39 using map_invalid_t = typename map_invalid<AN...>::type; 40 41 template<class T, class Selector> 42 struct map 43 { 44 typedef rxu::decay_t<T> source_value_type; 45 typedef rxu::decay_t<Selector> select_type; 46 typedef decltype((*(select_type*)nullptr)(*(source_value_type*)nullptr)) value_type; 47 select_type selector; 48 49 map(select_type s) 50 : selector(std::move(s)) 51 { 52 } 53 54 template<class Subscriber> 55 struct map_observer 56 { 57 typedef map_observer<Subscriber> this_type; 58 typedef decltype((*(select_type*)nullptr)(*(source_value_type*)nullptr)) value_type; 59 typedef rxu::decay_t<Subscriber> dest_type; 60 typedef observer<source_value_type, this_type> observer_type; 61 dest_type dest; 62 mutable select_type selector; 63 64 map_observer(dest_type d, select_type s) 65 : dest(std::move(d)) 66 , selector(std::move(s)) 67 { 68 } 69 template<class Value> 70 void on_next(Value&& v) const { 71 auto selected = on_exception( 72 [&](){ 73 return this->selector(std::forward<Value>(v));}, 74 dest); 75 if (selected.empty()) { 76 return; 77 } 78 dest.on_next(std::move(selected.get())); 79 } 80 void on_error(rxu::error_ptr e) const { 81 dest.on_error(e); 82 } 83 void on_completed() const { 84 dest.on_completed(); 85 } 86 87 static subscriber<source_value_type, observer_type> make(dest_type d, select_type s) { 88 auto cs = d.get_subscription(); 89 return make_subscriber<source_value_type>(std::move(cs), observer_type(this_type(std::move(d), std::move(s)))); 90 } 91 }; 92 93 template<class Subscriber> 94 auto operator()(Subscriber dest) const 95 -> decltype(map_observer<Subscriber>::make(std::move(dest), selector)) { 96 return map_observer<Subscriber>::make(std::move(dest), selector); 97 } 98 }; 99 100 } 101 102 /*! @copydoc rx-map.hpp 103 */ 104 template<class... AN> 105 auto map(AN&&... an) 106 -> operator_factory<map_tag, AN...> { 107 return operator_factory<map_tag, AN...>(std::make_tuple(std::forward<AN>(an)...)); 108 } 109 110 /*! @copydoc rx-map.hpp 111 */ 112 template<class... AN> 113 auto transform(AN&&... an) 114 -> operator_factory<map_tag, AN...> { 115 return operator_factory<map_tag, AN...>(std::make_tuple(std::forward<AN>(an)...)); 116 } 117 118 } 119 120 template<> 121 struct member_overload<map_tag> 122 { 123 template<class Observable, class Selector, 124 class Enabled = rxu::enable_if_all_true_type_t< 125 is_observable<Observable>>, 126 class ResolvedSelector = rxu::decay_t<Selector>, 127 class SourceValue = rxu::value_type_t<Observable>, 128 class Map = rxo::detail::map<SourceValue, ResolvedSelector>, 129 class Value = rxu::value_type_t<Map>> 130 static auto member(Observable&& o, Selector&& s) 131 -> decltype(o.template lift<Value>(Map(std::forward<Selector>(s)))) { 132 return o.template lift<Value>(Map(std::forward<Selector>(s))); 133 } 134 135 template<class... AN> 136 static operators::detail::map_invalid_t<AN...> member(const AN...) { 137 std::terminate(); 138 return {}; 139 static_assert(sizeof...(AN) == 10000, "map takes Selector"); 140 } 141 }; 142 143 } 144 145 #endif 146