688 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			688 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| /*! \file rx-reduce.hpp
 | |
| 
 | |
|     \brief For each item from this observable use Accumulator to combine items, when completed use ResultSelector to produce a value that will be emitted from the new observable that is returned.
 | |
| 
 | |
|     \tparam Seed            the type of the initial value for the accumulator
 | |
|     \tparam Accumulator     the type of the data accumulating function
 | |
|     \tparam ResultSelector  the type of the result producing function
 | |
| 
 | |
|     \param seed  the initial value for the accumulator
 | |
|     \param a     an accumulator function to be invoked on each item emitted by the source observable, the result of which will be used in the next accumulator call
 | |
|     \param rs    a result producing function that makes the final value from the last accumulator call result
 | |
| 
 | |
|     \return  An observable that emits a single item that is the result of accumulating the output from the items emitted by the source observable.
 | |
| 
 | |
|     Some basic reduce-type operators have already been implemented:
 | |
|     - rxcpp::operators::first
 | |
|     - rxcpp::operators::last
 | |
|     - rxcpp::operators::count
 | |
|     - rxcpp::operators::sum
 | |
|     - rxcpp::operators::average
 | |
|     - rxcpp::operators::min
 | |
|     - rxcpp::operators::max
 | |
| 
 | |
|     \sample
 | |
|     Geometric mean of source values:
 | |
|     \snippet reduce.cpp reduce sample
 | |
|     \snippet output.txt reduce sample
 | |
| 
 | |
|     If the source observable completes without emitting any items, the resulting observable emits the result of passing the initial seed to the result selector:
 | |
|     \snippet reduce.cpp reduce empty sample
 | |
|     \snippet output.txt reduce empty sample
 | |
| 
 | |
|     If the accumulator raises an exception, it is returned by the resulting observable in on_error:
 | |
|     \snippet reduce.cpp reduce exception from accumulator sample
 | |
|     \snippet output.txt reduce exception from accumulator sample
 | |
| 
 | |
|     The same for exceptions raised by the result selector:
 | |
|     \snippet reduce.cpp reduce exception from result selector sample
 | |
|     \snippet output.txt reduce exception from result selector sample
 | |
| */
 | |
| 
 | |
| #if !defined(RXCPP_OPERATORS_RX_REDUCE_HPP)
 | |
| #define RXCPP_OPERATORS_RX_REDUCE_HPP
 | |
| 
 | |
| #include "../rx-includes.hpp"
 | |
| 
 | |
| namespace rxcpp {
 | |
| 
 | |
| namespace operators {
 | |
| 
 | |
| namespace detail {
 | |
| 
 | |
| template<class... AN>
 | |
| struct reduce_invalid_arguments {};
 | |
| 
 | |
| template<class... AN>
 | |
| struct reduce_invalid : public rxo::operator_base<reduce_invalid_arguments<AN...>> {
 | |
|     using type = observable<reduce_invalid_arguments<AN...>, reduce_invalid<AN...>>;
 | |
| };
 | |
| template<class... AN>
 | |
| using reduce_invalid_t = typename reduce_invalid<AN...>::type;
 | |
| 
 | |
| template<class Seed, class ResultSelector>
 | |
| struct is_result_function_for {
 | |
| 
 | |
|     typedef rxu::decay_t<ResultSelector> result_selector_type;
 | |
|     typedef rxu::decay_t<Seed> seed_type;
 | |
| 
 | |
|     struct tag_not_valid {};
 | |
| 
 | |
|     template<class CS, class CRS>
 | |
|     static auto check(int) -> decltype((*(CRS*)nullptr)(*(CS*)nullptr));
 | |
|     template<class CS, class CRS>
 | |
|     static tag_not_valid check(...);
 | |
| 
 | |
|     typedef rxu::decay_t<decltype(check<seed_type, result_selector_type>(0))> type;
 | |
|     static const bool value = !std::is_same<type, tag_not_valid>::value;
 | |
| };
 | |
| 
 | |
| template<class T, class Observable, class Accumulator, class ResultSelector, class Seed>
 | |
| struct reduce_traits
 | |
| {
 | |
|     typedef rxu::decay_t<Observable> source_type;
 | |
|     typedef rxu::decay_t<Accumulator> accumulator_type;
 | |
|     typedef rxu::decay_t<ResultSelector> result_selector_type;
 | |
|     typedef rxu::decay_t<Seed> seed_type;
 | |
| 
 | |
|     typedef T source_value_type;
 | |
| 
 | |
|     typedef typename is_result_function_for<seed_type, result_selector_type>::type value_type;
 | |
| };
 | |
| 
 | |
| template<class T, class Observable, class Accumulator, class ResultSelector, class Seed>
 | |
| struct reduce : public operator_base<rxu::value_type_t<reduce_traits<T, Observable, Accumulator, ResultSelector, Seed>>>
 | |
| {
 | |
|     typedef reduce<T, Observable, Accumulator, ResultSelector, Seed> this_type;
 | |
|     typedef reduce_traits<T, Observable, Accumulator, ResultSelector, Seed> traits;
 | |
| 
 | |
|     typedef typename traits::source_type source_type;
 | |
|     typedef typename traits::accumulator_type accumulator_type;
 | |
|     typedef typename traits::result_selector_type result_selector_type;
 | |
|     typedef typename traits::seed_type seed_type;
 | |
| 
 | |
|     typedef typename traits::source_value_type source_value_type;
 | |
|     typedef typename traits::value_type value_type;
 | |
| 
 | |
|     struct reduce_initial_type
 | |
|     {
 | |
|         ~reduce_initial_type()
 | |
|         {
 | |
|         }
 | |
|         reduce_initial_type(source_type o, accumulator_type a, result_selector_type rs, seed_type s)
 | |
|             : source(std::move(o))
 | |
|             , accumulator(std::move(a))
 | |
|             , result_selector(std::move(rs))
 | |
|             , seed(std::move(s))
 | |
|         {
 | |
|         }
 | |
|         source_type source;
 | |
|         accumulator_type accumulator;
 | |
|         result_selector_type result_selector;
 | |
|         seed_type seed;
 | |
| 
 | |
|     private:
 | |
|         reduce_initial_type& operator=(reduce_initial_type o) RXCPP_DELETE;
 | |
|     };
 | |
|     reduce_initial_type initial;
 | |
| 
 | |
|     ~reduce()
 | |
|     {
 | |
|     }
 | |
|     reduce(source_type o, accumulator_type a, result_selector_type rs, seed_type s)
 | |
|         : initial(std::move(o), std::move(a), std::move(rs), std::move(s))
 | |
|     {
 | |
|     }
 | |
|     template<class Subscriber>
 | |
|     void on_subscribe(Subscriber o) const {
 | |
|         struct reduce_state_type
 | |
|             : public reduce_initial_type
 | |
|             , public std::enable_shared_from_this<reduce_state_type>
 | |
|         {
 | |
|             reduce_state_type(reduce_initial_type i, Subscriber scrbr)
 | |
|                 : reduce_initial_type(i)
 | |
|                 , source(i.source)
 | |
|                 , current(reduce_initial_type::seed)
 | |
|                 , out(std::move(scrbr))
 | |
|             {
 | |
|             }
 | |
|             source_type source;
 | |
|             seed_type current;
 | |
|             Subscriber out;
 | |
| 
 | |
|         private:
 | |
|             reduce_state_type& operator=(reduce_state_type o) RXCPP_DELETE;
 | |
|         };
 | |
|         auto state = std::make_shared<reduce_state_type>(initial, std::move(o));
 | |
|         state->source.subscribe(
 | |
|             state->out,
 | |
|         // on_next
 | |
|             [state](T t) {
 | |
|                 seed_type next = state->accumulator(std::move(state->current), std::move(t));
 | |
|                 state->current = std::move(next);
 | |
|             },
 | |
|         // on_error
 | |
|             [state](rxu::error_ptr e) {
 | |
|                 state->out.on_error(e);
 | |
|             },
 | |
|         // on_completed
 | |
|             [state]() {
 | |
|                 auto result = on_exception(
 | |
|                     [&](){return state->result_selector(std::move(state->current));},
 | |
|                     state->out);
 | |
|                 if (result.empty()) {
 | |
|                     return;
 | |
|                 }
 | |
|                 state->out.on_next(std::move(result.get()));
 | |
|                 state->out.on_completed();
 | |
|             }
 | |
|         );
 | |
|     }
 | |
| private:
 | |
|     reduce& operator=(reduce o) RXCPP_DELETE;
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct initialize_seeder {
 | |
|     typedef T seed_type;
 | |
|     static seed_type seed() {
 | |
|         return seed_type{};
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct average {
 | |
|     struct seed_type
 | |
|     {
 | |
|         seed_type()
 | |
|             : value()
 | |
|             , count(0)
 | |
|         {
 | |
|         }
 | |
|         rxu::maybe<T> value;
 | |
|         int count;
 | |
|         rxu::detail::maybe<double> stage;
 | |
|     };
 | |
|     static seed_type seed() {
 | |
|         return seed_type{};
 | |
|     }
 | |
|     template<class U>
 | |
|     seed_type operator()(seed_type a, U&& v) {
 | |
|         if (a.count != 0 &&
 | |
|             (a.count == std::numeric_limits<int>::max() ||
 | |
|             ((v > 0) && (*(a.value) > (std::numeric_limits<T>::max() - v))) ||
 | |
|             ((v < 0) && (*(a.value) < (std::numeric_limits<T>::min() - v))))) {
 | |
|             // would overflow, calc existing and reset for next batch
 | |
|             // this will add error to the final result, but the alternative
 | |
|             // is to fail on overflow
 | |
|             double avg = static_cast<double>(*(a.value)) / a.count;
 | |
|             if (!a.stage.empty()) {
 | |
|                 a.stage.reset((*a.stage + avg) / 2);
 | |
|             } else {
 | |
|                 a.stage.reset(avg);
 | |
|             }
 | |
|             a.value.reset(std::forward<U>(v));
 | |
|             a.count = 1;
 | |
|         } else if (a.value.empty()) {
 | |
|             a.value.reset(std::forward<U>(v));
 | |
|             a.count = 1;
 | |
|         } else {
 | |
|             *(a.value) += v;
 | |
|             ++a.count;
 | |
|         }
 | |
|         return a;
 | |
|     }
 | |
|     double operator()(seed_type a) {
 | |
|         if (!a.value.empty()) {
 | |
|             double avg = static_cast<double>(*(a.value)) / a.count;
 | |
|             if (!a.stage.empty()) {
 | |
|                 avg = (*a.stage + avg) / 2;
 | |
|             }
 | |
|             return avg;
 | |
|         }
 | |
|         rxu::throw_exception(rxcpp::empty_error("average() requires a stream with at least one value"));
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct sum {
 | |
|     typedef rxu::maybe<T> seed_type;
 | |
|     static seed_type seed() {
 | |
|         return seed_type();
 | |
|     }
 | |
|     template<class U>
 | |
|     seed_type operator()(seed_type a, U&& v) const {
 | |
|         if (a.empty())
 | |
|             a.reset(std::forward<U>(v));
 | |
|         else
 | |
|             *a = *a + v;
 | |
|         return a;
 | |
|     }
 | |
|     T operator()(seed_type a) const {
 | |
|         if (a.empty())
 | |
|             rxu::throw_exception(rxcpp::empty_error("sum() requires a stream with at least one value"));
 | |
|         return *a;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct max {
 | |
|     typedef rxu::maybe<T> seed_type;
 | |
|     static seed_type seed() {
 | |
|         return seed_type();
 | |
|     }
 | |
|     template<class U>
 | |
|     seed_type operator()(seed_type a, U&& v) {
 | |
|         if (a.empty() || *a < v)
 | |
|             a.reset(std::forward<U>(v));
 | |
|         return a;
 | |
|     }
 | |
|     T operator()(seed_type a) {
 | |
|         if (a.empty())
 | |
|             rxu::throw_exception(rxcpp::empty_error("max() requires a stream with at least one value"));
 | |
|         return *a;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct min {
 | |
|     typedef rxu::maybe<T> seed_type;
 | |
|     static seed_type seed() {
 | |
|         return seed_type();
 | |
|     }
 | |
|     template<class U>
 | |
|     seed_type operator()(seed_type a, U&& v) {
 | |
|         if (a.empty() || v < *a)
 | |
|             a.reset(std::forward<U>(v));
 | |
|         return a;
 | |
|     }
 | |
|     T operator()(seed_type a) {
 | |
|         if (a.empty())
 | |
|             rxu::throw_exception(rxcpp::empty_error("min() requires a stream with at least one value"));
 | |
|         return *a;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct first {
 | |
|     using seed_type = rxu::maybe<T>;
 | |
|     static seed_type seed() {
 | |
|         return seed_type();
 | |
|     }
 | |
|     template<class U>
 | |
|     seed_type operator()(seed_type a, U&& v) {
 | |
|         a.reset(std::forward<U>(v));
 | |
|         return a;
 | |
|     }
 | |
|     T operator()(seed_type a) {
 | |
|         if (a.empty()) {
 | |
|             rxu::throw_exception(rxcpp::empty_error("first() requires a stream with at least one value"));
 | |
|         }
 | |
|         return *a;
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct last {
 | |
|     using seed_type = rxu::maybe<T>;
 | |
|     static seed_type seed() {
 | |
|         return seed_type();
 | |
|     }
 | |
|     template<class U>
 | |
|     seed_type operator()(seed_type a, U&& v) {
 | |
|         a.reset(std::forward<U>(v));
 | |
|         return a;
 | |
|     }
 | |
|     T operator()(seed_type a) {
 | |
|         if (a.empty()) {
 | |
|             rxu::throw_exception(rxcpp::empty_error("last() requires a stream with at least one value"));
 | |
|         }
 | |
|         return *a;
 | |
|     }
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| /*! @copydoc rx-reduce.hpp
 | |
| */
 | |
| template<class... AN>
 | |
| auto reduce(AN&&... an)
 | |
|     ->     operator_factory<reduce_tag, AN...> {
 | |
|     return operator_factory<reduce_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
 | |
| }
 | |
| 
 | |
| /*! @copydoc rx-reduce.hpp
 | |
| */
 | |
| template<class... AN>
 | |
| auto accumulate(AN&&... an)
 | |
|     ->     operator_factory<reduce_tag, AN...> {
 | |
|     return operator_factory<reduce_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by sending only the first item.
 | |
| 
 | |
|     \return  An observable that emits only the very first item emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp first sample
 | |
|     \snippet output.txt first sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp first empty sample
 | |
|     \snippet output.txt first empty sample
 | |
| */
 | |
| inline auto first()
 | |
|     ->     operator_factory<first_tag> {
 | |
|     return operator_factory<first_tag>(std::tuple<>{});
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by sending only the last item.
 | |
| 
 | |
|     \return  An observable that emits only the very last item emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp last sample
 | |
|     \snippet output.txt last sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp last empty sample
 | |
|     \snippet output.txt last empty sample
 | |
| */
 | |
| inline auto last()
 | |
|     ->     operator_factory<last_tag> {
 | |
|     return operator_factory<last_tag>(std::tuple<>{});
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by incrementing a count.
 | |
| 
 | |
|     \return  An observable that emits a single item: the number of elements emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp count sample
 | |
|     \snippet output.txt count sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp count error sample
 | |
|     \snippet output.txt count error sample
 | |
| */
 | |
| inline auto count()
 | |
|     ->     operator_factory<reduce_tag, int, rxu::count, rxu::detail::take_at<0>> {
 | |
|     return operator_factory<reduce_tag, int, rxu::count, rxu::detail::take_at<0>>(std::make_tuple(0, rxu::count(), rxu::take_at<0>()));
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by adding to the previous values and then dividing by the number of items at the end.
 | |
| 
 | |
|     \return  An observable that emits a single item: the average of elements emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp average sample
 | |
|     \snippet output.txt average sample
 | |
| 
 | |
|     When the source observable completes without emitting any items:
 | |
|     \snippet math.cpp average empty sample
 | |
|     \snippet output.txt average empty sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp average error sample
 | |
|     \snippet output.txt average error sample
 | |
| */
 | |
| inline auto average()
 | |
|     ->     operator_factory<average_tag> {
 | |
|     return operator_factory<average_tag>(std::tuple<>{});
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by adding to the previous items.
 | |
| 
 | |
|     \return  An observable that emits a single item: the sum of elements emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp sum sample
 | |
|     \snippet output.txt sum sample
 | |
| 
 | |
|     When the source observable completes without emitting any items:
 | |
|     \snippet math.cpp sum empty sample
 | |
|     \snippet output.txt sum empty sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp sum error sample
 | |
|     \snippet output.txt sum error sample
 | |
| */
 | |
| inline auto sum()
 | |
|     ->     operator_factory<sum_tag> {
 | |
|     return operator_factory<sum_tag>(std::tuple<>{});
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by taking the min value of the previous items.
 | |
| 
 | |
|     \return  An observable that emits a single item: the min of elements emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp min sample
 | |
|     \snippet output.txt min sample
 | |
| 
 | |
|     When the source observable completes without emitting any items:
 | |
|     \snippet math.cpp min empty sample
 | |
|     \snippet output.txt min empty sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp min error sample
 | |
|     \snippet output.txt min error sample
 | |
| */
 | |
| inline auto min()
 | |
|     ->     operator_factory<min_tag> {
 | |
|     return operator_factory<min_tag>(std::tuple<>{});
 | |
| }
 | |
| 
 | |
| /*! \brief For each item from this observable reduce it by taking the max value of the previous items.
 | |
| 
 | |
|     \return  An observable that emits a single item: the max of elements emitted by the source observable.
 | |
| 
 | |
|     \sample
 | |
|     \snippet math.cpp max sample
 | |
|     \snippet output.txt max sample
 | |
| 
 | |
|     When the source observable completes without emitting any items:
 | |
|     \snippet math.cpp max empty sample
 | |
|     \snippet output.txt max empty sample
 | |
| 
 | |
|     When the source observable calls on_error:
 | |
|     \snippet math.cpp max error sample
 | |
|     \snippet output.txt max error sample
 | |
| */
 | |
| inline auto max()
 | |
|     ->     operator_factory<max_tag> {
 | |
|     return operator_factory<max_tag>(std::tuple<>{});
 | |
| }
 | |
| 
 | |
| }
 | |
| 
 | |
| template<>
 | |
| struct member_overload<reduce_tag>
 | |
| {
 | |
| 
 | |
|     template<class Observable, class Seed, class Accumulator, class ResultSelector,
 | |
|         class Reduce = rxo::detail::reduce<rxu::value_type_t<Observable>, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class Value = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<Value, Reduce>>
 | |
|     static Result member(Observable&& o, Seed&& s, Accumulator&& a, ResultSelector&& r)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), std::forward<Accumulator>(a), std::forward<ResultSelector>(r), std::forward<Seed>(s)));
 | |
|     }
 | |
| 
 | |
|     template<class Observable, class Seed, class Accumulator,
 | |
|         class ResultSelector=rxu::detail::take_at<0>,
 | |
|         class Reduce = rxo::detail::reduce<rxu::value_type_t<Observable>, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class Value = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<Value, Reduce>>
 | |
|     static Result member(Observable&& o, Seed&& s, Accumulator&& a)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), std::forward<Accumulator>(a), rxu::detail::take_at<0>(), std::forward<Seed>(s)));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "reduce takes (Seed, Accumulator, optional ResultSelector), Accumulator takes (Seed, Observable::value_type) -> Seed, ResultSelector takes (Observable::value_type) -> ResultValue");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct member_overload<first_tag>
 | |
| {
 | |
|     template<class Observable,
 | |
|         class SValue = rxu::value_type_t<Observable>,
 | |
|         class Operation = operators::detail::first<SValue>,
 | |
|         class Seed = decltype(Operation::seed()),
 | |
|         class Accumulator = Operation,
 | |
|         class ResultSelector = Operation,
 | |
|         class TakeOne = decltype(((rxu::decay_t<Observable>*)nullptr)->take(1)),
 | |
|         class Reduce = rxo::detail::reduce<SValue, rxu::decay_t<TakeOne>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class RValue = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<RValue, Reduce>>
 | |
|     static Result member(Observable&& o)
 | |
|     {
 | |
|         return Result(Reduce(o.take(1), Operation{}, Operation{}, Operation::seed()));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "first does not support Observable::value_type");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct member_overload<last_tag>
 | |
| {
 | |
|     template<class Observable,
 | |
|         class SValue = rxu::value_type_t<Observable>,
 | |
|         class Operation = operators::detail::last<SValue>,
 | |
|         class Seed = decltype(Operation::seed()),
 | |
|         class Accumulator = Operation,
 | |
|         class ResultSelector = Operation,
 | |
|         class Reduce = rxo::detail::reduce<SValue, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class RValue = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<RValue, Reduce>>
 | |
|     static Result member(Observable&& o)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), Operation{}, Operation{}, Operation::seed()));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "last does not support Observable::value_type");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct member_overload<sum_tag>
 | |
| {
 | |
|     template<class Observable,
 | |
|         class SValue = rxu::value_type_t<Observable>,
 | |
|         class Operation = operators::detail::sum<SValue>,
 | |
|         class Seed = decltype(Operation::seed()),
 | |
|         class Accumulator = Operation,
 | |
|         class ResultSelector = Operation,
 | |
|         class Reduce = rxo::detail::reduce<SValue, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class RValue = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<RValue, Reduce>>
 | |
|     static Result member(Observable&& o)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), Operation{}, Operation{}, Operation::seed()));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "sum does not support Observable::value_type");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct member_overload<average_tag>
 | |
| {
 | |
|     template<class Observable,
 | |
|         class SValue = rxu::value_type_t<Observable>,
 | |
|         class Operation = operators::detail::average<SValue>,
 | |
|         class Seed = decltype(Operation::seed()),
 | |
|         class Accumulator = Operation,
 | |
|         class ResultSelector = Operation,
 | |
|         class Reduce = rxo::detail::reduce<SValue, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class RValue = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<RValue, Reduce>>
 | |
|     static Result member(Observable&& o)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), Operation{}, Operation{}, Operation::seed()));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "average does not support Observable::value_type");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct member_overload<max_tag>
 | |
| {
 | |
|     template<class Observable,
 | |
|         class SValue = rxu::value_type_t<Observable>,
 | |
|         class Operation = operators::detail::max<SValue>,
 | |
|         class Seed = decltype(Operation::seed()),
 | |
|         class Accumulator = Operation,
 | |
|         class ResultSelector = Operation,
 | |
|         class Reduce = rxo::detail::reduce<SValue, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class RValue = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<RValue, Reduce>>
 | |
|     static Result member(Observable&& o)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), Operation{}, Operation{}, Operation::seed()));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "max does not support Observable::value_type");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct member_overload<min_tag>
 | |
| {
 | |
|     template<class Observable,
 | |
|         class SValue = rxu::value_type_t<Observable>,
 | |
|         class Operation = operators::detail::min<SValue>,
 | |
|         class Seed = decltype(Operation::seed()),
 | |
|         class Accumulator = Operation,
 | |
|         class ResultSelector = Operation,
 | |
|         class Reduce = rxo::detail::reduce<SValue, rxu::decay_t<Observable>, rxu::decay_t<Accumulator>, rxu::decay_t<ResultSelector>, rxu::decay_t<Seed>>,
 | |
|         class RValue = rxu::value_type_t<Reduce>,
 | |
|         class Result = observable<RValue, Reduce>>
 | |
|     static Result member(Observable&& o)
 | |
|     {
 | |
|         return Result(Reduce(std::forward<Observable>(o), Operation{}, Operation{}, Operation::seed()));
 | |
|     }
 | |
| 
 | |
|     template<class... AN>
 | |
|     static operators::detail::reduce_invalid_t<AN...> member(AN...) {
 | |
|         std::terminate();
 | |
|         return {};
 | |
|         static_assert(sizeof...(AN) == 10000, "min does not support Observable::value_type");
 | |
|     }
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif
 |