-
Notifications
You must be signed in to change notification settings - Fork 37
Try to stabilize disposables logic #673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e3706c8
b79ce00
c4decc8
652e362
1cccfe4
017bd10
c525a79
e897c6e
e4d2545
44f0d67
14656b6
66a95f8
6ff468a
f54ed0d
cf7d666
48936b9
db6f58c
a3145c7
793aac4
af429e4
3b02d73
c6fe6da
29c8e17
a371479
6095b8d
2006590
be3d80d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,33 +34,29 @@ namespace rpp::operators::details | |
| }; | ||
|
|
||
| template<rpp::constraint::observable TObservable, rpp::constraint::observer TObserver> | ||
| class concat_state_t final : public std::enable_shared_from_this<concat_state_t<TObservable, TObserver>> | ||
| class concat_disposable final : public rpp::refcount_disposable | ||
| { | ||
| public: | ||
| concat_state_t(TObserver&& observer) | ||
| concat_disposable(TObserver&& observer) | ||
| : m_observer{std::move(observer)} | ||
| { | ||
| const auto d = disposable_wrapper_impl<refcount_disposable>::make(); | ||
| m_disposable = d.lock(); | ||
| get_observer()->set_upstream(d); | ||
| } | ||
|
|
||
| rpp::utils::pointer_under_lock<TObserver> get_observer() { return m_observer; } | ||
| rpp::utils::pointer_under_lock<std::queue<TObservable>> get_queue() { return m_queue; } | ||
| const std::shared_ptr<refcount_disposable>& get_disposable() const { return m_disposable; } | ||
|
|
||
| std::atomic<ConcatStage>& stage() { return m_stage; } | ||
|
|
||
| void drain(rpp::composite_disposable_wrapper refcounted) | ||
| { | ||
| while (!m_disposable->is_disposed()) | ||
| while (!is_disposed()) | ||
| { | ||
| const auto observable = get_observable(); | ||
| if (!observable) | ||
| { | ||
| stage().store(ConcatStage::None, std::memory_order::relaxed); | ||
| refcounted.dispose(); | ||
| if (m_disposable->is_disposed()) | ||
| if (is_disposed()) | ||
| get_observer()->on_completed(); | ||
| return; | ||
| } | ||
|
|
@@ -78,13 +74,11 @@ namespace rpp::operators::details | |
| drain(refcounted); | ||
| } | ||
|
|
||
|
|
||
| private: | ||
| bool handle_observable_impl(const rpp::constraint::decayed_same_as<TObservable> auto& observable, rpp::composite_disposable_wrapper refcounted) | ||
| { | ||
| stage().store(ConcatStage::Draining, std::memory_order::relaxed); | ||
| refcounted.clear(); | ||
| observable.subscribe(concat_inner_observer_strategy<TObservable, TObserver>{this->shared_from_this(), std::move(refcounted)}); | ||
| observable.subscribe(concat_inner_observer_strategy<TObservable, TObserver>{disposable_wrapper_impl<concat_disposable>{wrapper_from_this()}.lock(), std::move(refcounted)}); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verify safe usage of Ensure that |
||
|
|
||
| ConcatStage current = ConcatStage::Draining; | ||
| return stage().compare_exchange_strong(current, ConcatStage::Processing, std::memory_order::seq_cst); | ||
|
|
@@ -102,7 +96,6 @@ namespace rpp::operators::details | |
| } | ||
|
|
||
| private: | ||
| std::shared_ptr<refcount_disposable> m_disposable{}; | ||
| rpp::utils::value_with_mutex<TObserver> m_observer; | ||
| rpp::utils::value_with_mutex<std::queue<TObservable>> m_queue; | ||
| std::atomic<ConcatStage> m_stage{}; | ||
|
|
@@ -111,23 +104,23 @@ namespace rpp::operators::details | |
| template<rpp::constraint::observable TObservable, rpp::constraint::observer TObserver> | ||
| struct concat_observer_strategy_base | ||
| { | ||
| concat_observer_strategy_base(std::shared_ptr<concat_state_t<TObservable, TObserver>> state, rpp::composite_disposable_wrapper refcounted) | ||
| : state{std::move(state)} | ||
| concat_observer_strategy_base(std::shared_ptr<concat_disposable<TObservable, TObserver>> disposable, rpp::composite_disposable_wrapper refcounted) | ||
| : disposable{std::move(disposable)} | ||
| , refcounted{std::move(refcounted)} | ||
| { | ||
| } | ||
|
|
||
| concat_observer_strategy_base(std::shared_ptr<concat_state_t<TObservable, TObserver>> state) | ||
| : concat_observer_strategy_base{state, state->get_disposable()->add_ref(refcount_disposable::Mode::StrongRefRefSource)} | ||
| concat_observer_strategy_base(std::shared_ptr<concat_disposable<TObservable, TObserver>> disposable) | ||
| : concat_observer_strategy_base{disposable, disposable->add_ref()} | ||
| { | ||
| } | ||
|
|
||
| std::shared_ptr<concat_state_t<TObservable, TObserver>> state; | ||
| rpp::composite_disposable_wrapper refcounted; | ||
| std::shared_ptr<concat_disposable<TObservable, TObserver>> disposable; | ||
| rpp::composite_disposable_wrapper refcounted; | ||
|
|
||
| void on_error(const std::exception_ptr& err) const | ||
| { | ||
| state->get_observer()->on_error(err); | ||
| disposable->get_observer()->on_error(err); | ||
| } | ||
|
|
||
| void set_upstream(const disposable_wrapper& d) const { refcounted.add(d); } | ||
|
|
@@ -138,55 +131,68 @@ namespace rpp::operators::details | |
| template<rpp::constraint::observable TObservable, rpp::constraint::observer TObserver> | ||
| struct concat_inner_observer_strategy : public concat_observer_strategy_base<TObservable, TObserver> | ||
| { | ||
| static constexpr auto preferred_disposables_mode = rpp::details::observers::disposables_mode::Auto; | ||
| static constexpr auto preferred_disposables_mode = rpp::details::observers::disposables_mode::None; | ||
|
|
||
| using base = concat_observer_strategy_base<TObservable, TObserver>; | ||
| using base::concat_observer_strategy_base; | ||
|
|
||
| template<typename T> | ||
| void on_next(T&& v) const | ||
| { | ||
| base::state->get_observer()->on_next(std::forward<T>(v)); | ||
| base::disposable->get_observer()->on_next(std::forward<T>(v)); | ||
| } | ||
|
|
||
| void on_completed() const | ||
| { | ||
| base::refcounted.clear(); | ||
|
|
||
| ConcatStage current{ConcatStage::Draining}; | ||
| if (base::state->stage().compare_exchange_strong(current, ConcatStage::CompletedWhileDraining, std::memory_order::seq_cst)) | ||
| if (base::disposable->stage().compare_exchange_strong(current, ConcatStage::CompletedWhileDraining, std::memory_order::seq_cst)) | ||
| return; | ||
|
|
||
| assert(current == ConcatStage::Processing); | ||
|
|
||
| base::state->drain(base::refcounted); | ||
| base::disposable->drain(base::refcounted); | ||
| } | ||
| }; | ||
|
|
||
| template<rpp::constraint::observable TObservable, rpp::constraint::observer TObserver> | ||
| struct concat_observer_strategy : public concat_observer_strategy_base<TObservable, TObserver> | ||
| { | ||
| using base = concat_observer_strategy_base<TObservable, TObserver>; | ||
| using base = concat_observer_strategy_base<TObservable, TObserver>; | ||
|
|
||
| static constexpr auto preferred_disposables_mode = rpp::details::observers::disposables_mode::None; | ||
|
|
||
| concat_observer_strategy(TObserver&& observer) | ||
| : base{std::make_shared<concat_state_t<TObservable, TObserver>>(std::move(observer))} | ||
| : base{init_state(std::move(observer))} | ||
| { | ||
| } | ||
|
|
||
| template<typename T> | ||
| void on_next(T&& v) const | ||
| { | ||
| ConcatStage current = ConcatStage::None; | ||
| if (base::state->stage().compare_exchange_strong(current, ConcatStage::Draining, std::memory_order::seq_cst)) | ||
| base::state->handle_observable(std::forward<T>(v), base::state->get_disposable()->add_ref(refcount_disposable::Mode::StrongRefRefSource)); | ||
| if (base::disposable->stage().compare_exchange_strong(current, ConcatStage::Draining, std::memory_order::seq_cst)) | ||
| base::disposable->handle_observable(std::forward<T>(v), base::disposable->add_ref()); | ||
| else | ||
| base::state->get_queue()->push(std::forward<T>(v)); | ||
| base::disposable->get_queue()->push(std::forward<T>(v)); | ||
| } | ||
|
|
||
| void on_completed() const | ||
| { | ||
| base::refcounted.dispose(); | ||
| if (base::state->get_disposable()->is_disposed()) | ||
| base::state->get_observer()->on_completed(); | ||
| if (base::disposable->is_disposed()) | ||
| base::disposable->get_observer()->on_completed(); | ||
| } | ||
|
|
||
|
|
||
| private: | ||
| static std::shared_ptr<concat_disposable<TObservable, TObserver>> init_state(TObserver&& observer) | ||
| { | ||
| const auto d = disposable_wrapper_impl<concat_disposable<TObservable, TObserver>>::make(std::move(observer)); | ||
| auto ptr = d.lock(); | ||
| ptr->get_observer()->set_upstream(d.as_weak()); | ||
| return ptr; | ||
|
Comment on lines
+190
to
+195
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure In |
||
| } | ||
| }; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.