// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. #pragma once /*! \file rx-ref_count.hpp \brief takes a connectable_observable source and uses a ref_count of the subscribers to control the connection to the published source. The first subscription will cause a call to connect() and the last unsubscribe will unsubscribe the connection. \return An observable that emitting the items from its source. */ #if !defined(RXCPP_OPERATORS_RX_REF_COUNT_HPP) #define RXCPP_OPERATORS_RX_REF_COUNT_HPP #include "../rx-includes.hpp" namespace rxcpp { namespace operators { namespace detail { template struct ref_count_invalid_arguments {}; template struct ref_count_invalid : public rxo::operator_base> { using type = observable, ref_count_invalid>; }; template using ref_count_invalid_t = typename ref_count_invalid::type; template struct ref_count : public operator_base { typedef rxu::decay_t source_type; struct ref_count_state : public std::enable_shared_from_this { explicit ref_count_state(source_type o) : source(std::move(o)) , subscribers(0) { } source_type source; std::mutex lock; long subscribers; composite_subscription connection; }; std::shared_ptr state; explicit ref_count(source_type o) : state(std::make_shared(std::move(o))) { } template void on_subscribe(Subscriber&& o) const { std::unique_lock guard(state->lock); auto needConnect = ++state->subscribers == 1; auto keepAlive = state; guard.unlock(); o.add( [keepAlive](){ std::unique_lock guard_unsubscribe(keepAlive->lock); if (--keepAlive->subscribers == 0) { keepAlive->connection.unsubscribe(); keepAlive->connection = composite_subscription(); } }); keepAlive->source.subscribe(std::forward(o)); if (needConnect) { keepAlive->source.connect(keepAlive->connection); } } }; } /*! @copydoc rx-ref_count.hpp */ template auto ref_count(AN&&... an) -> operator_factory { return operator_factory(std::make_tuple(std::forward(an)...)); } } template<> struct member_overload { template>, class SourceValue = rxu::value_type_t, class RefCount = rxo::detail::ref_count>, class Value = rxu::value_type_t, class Result = observable > static Result member(ConnectableObservable&& o) { return Result(RefCount(std::forward(o))); } template static operators::detail::ref_count_invalid_t member(AN...) { std::terminate(); return {}; static_assert(sizeof...(AN) == 10000, "ref_count takes no arguments"); } }; } #endif