feat add rxcpp
This commit is contained in:
107
3party/rxcpp/subjects/rx-behavior.hpp
Normal file
107
3party/rxcpp/subjects/rx-behavior.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_RX_BEHAVIOR_HPP)
|
||||
#define RXCPP_RX_BEHAVIOR_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace subjects {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class behavior_observer : public detail::multicast_observer<T>
|
||||
{
|
||||
typedef behavior_observer<T> this_type;
|
||||
typedef detail::multicast_observer<T> base_type;
|
||||
|
||||
class behavior_observer_state : public std::enable_shared_from_this<behavior_observer_state>
|
||||
{
|
||||
mutable std::mutex lock;
|
||||
mutable T value;
|
||||
|
||||
public:
|
||||
behavior_observer_state(T first)
|
||||
: value(first)
|
||||
{
|
||||
}
|
||||
|
||||
void reset(T v) const {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
value = std::move(v);
|
||||
}
|
||||
T get() const {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<behavior_observer_state> state;
|
||||
|
||||
public:
|
||||
behavior_observer(T f, composite_subscription l)
|
||||
: base_type(l)
|
||||
, state(std::make_shared<behavior_observer_state>(std::move(f)))
|
||||
{
|
||||
}
|
||||
|
||||
subscriber<T> get_subscriber() const {
|
||||
return make_subscriber<T>(this->get_id(), this->get_subscription(), observer<T, detail::behavior_observer<T>>(*this)).as_dynamic();
|
||||
}
|
||||
|
||||
T get_value() const {
|
||||
return state->get();
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void on_next(V v) const {
|
||||
state->reset(v);
|
||||
base_type::on_next(std::move(v));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class behavior
|
||||
{
|
||||
detail::behavior_observer<T> s;
|
||||
|
||||
public:
|
||||
explicit behavior(T f, composite_subscription cs = composite_subscription())
|
||||
: s(std::move(f), cs)
|
||||
{
|
||||
}
|
||||
|
||||
bool has_observers() const {
|
||||
return s.has_observers();
|
||||
}
|
||||
|
||||
T get_value() const {
|
||||
return s.get_value();
|
||||
}
|
||||
|
||||
subscriber<T> get_subscriber() const {
|
||||
return s.get_subscriber();
|
||||
}
|
||||
|
||||
observable<T> get_observable() const {
|
||||
auto keepAlive = s;
|
||||
return make_observable_dynamic<T>([keepAlive](subscriber<T> o){
|
||||
if (keepAlive.get_subscription().is_subscribed()) {
|
||||
o.on_next(keepAlive.get_value());
|
||||
}
|
||||
keepAlive.add(keepAlive.get_subscriber(), std::move(o));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
186
3party/rxcpp/subjects/rx-replaysubject.hpp
Normal file
186
3party/rxcpp/subjects/rx-replaysubject.hpp
Normal file
@@ -0,0 +1,186 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_RX_REPLAYSUBJECT_HPP)
|
||||
#define RXCPP_RX_REPLAYSUBJECT_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace subjects {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Coordination>
|
||||
struct replay_traits
|
||||
{
|
||||
typedef rxu::maybe<std::size_t> count_type;
|
||||
typedef rxu::maybe<rxsc::scheduler::clock_type::duration> period_type;
|
||||
typedef rxsc::scheduler::clock_type::time_point time_point_type;
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
};
|
||||
|
||||
template<class T, class Coordination>
|
||||
class replay_observer : public detail::multicast_observer<T>
|
||||
{
|
||||
typedef replay_observer<T, Coordination> this_type;
|
||||
typedef detail::multicast_observer<T> base_type;
|
||||
|
||||
typedef replay_traits<Coordination> traits;
|
||||
typedef typename traits::count_type count_type;
|
||||
typedef typename traits::period_type period_type;
|
||||
typedef typename traits::time_point_type time_point_type;
|
||||
typedef typename traits::coordination_type coordination_type;
|
||||
typedef typename traits::coordinator_type coordinator_type;
|
||||
|
||||
class replay_observer_state : public std::enable_shared_from_this<replay_observer_state>
|
||||
{
|
||||
mutable std::mutex lock;
|
||||
mutable std::list<T> values;
|
||||
mutable std::list<time_point_type> time_points;
|
||||
mutable count_type count;
|
||||
mutable period_type period;
|
||||
mutable composite_subscription replayLifetime;
|
||||
public:
|
||||
mutable coordination_type coordination;
|
||||
mutable coordinator_type coordinator;
|
||||
|
||||
private:
|
||||
void remove_oldest() const {
|
||||
values.pop_front();
|
||||
if (!period.empty()) {
|
||||
time_points.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
~replay_observer_state(){
|
||||
replayLifetime.unsubscribe();
|
||||
}
|
||||
explicit replay_observer_state(count_type _count, period_type _period, coordination_type _coordination, coordinator_type _coordinator, composite_subscription _replayLifetime)
|
||||
: count(_count)
|
||||
, period(_period)
|
||||
, replayLifetime(_replayLifetime)
|
||||
, coordination(std::move(_coordination))
|
||||
, coordinator(std::move(_coordinator))
|
||||
{
|
||||
}
|
||||
|
||||
void add(T v) const {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
|
||||
if (!count.empty()) {
|
||||
if (values.size() == count.get())
|
||||
remove_oldest();
|
||||
}
|
||||
|
||||
if (!period.empty()) {
|
||||
auto now = coordination.now();
|
||||
while (!time_points.empty() && (now - time_points.front() > period.get()))
|
||||
remove_oldest();
|
||||
time_points.push_back(now);
|
||||
}
|
||||
|
||||
values.push_back(std::move(v));
|
||||
}
|
||||
std::list<T> get() const {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
return values;
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<replay_observer_state> state;
|
||||
|
||||
public:
|
||||
replay_observer(count_type count, period_type period, coordination_type coordination, composite_subscription replayLifetime, composite_subscription subscriberLifetime)
|
||||
: base_type(subscriberLifetime)
|
||||
{
|
||||
replayLifetime.add(subscriberLifetime);
|
||||
auto coordinator = coordination.create_coordinator(replayLifetime);
|
||||
state = std::make_shared<replay_observer_state>(std::move(count), std::move(period), std::move(coordination), std::move(coordinator), std::move(replayLifetime));
|
||||
}
|
||||
|
||||
subscriber<T> get_subscriber() const {
|
||||
return make_subscriber<T>(this->get_id(), this->get_subscription(), observer<T, detail::replay_observer<T, Coordination>>(*this)).as_dynamic();
|
||||
}
|
||||
|
||||
std::list<T> get_values() const {
|
||||
return state->get();
|
||||
}
|
||||
|
||||
coordinator_type& get_coordinator() const {
|
||||
return state->coordinator;
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void on_next(V v) const {
|
||||
state->add(v);
|
||||
base_type::on_next(std::move(v));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<class T, class Coordination>
|
||||
class replay
|
||||
{
|
||||
typedef detail::replay_traits<Coordination> traits;
|
||||
typedef typename traits::count_type count_type;
|
||||
typedef typename traits::period_type period_type;
|
||||
typedef typename traits::time_point_type time_point_type;
|
||||
|
||||
detail::replay_observer<T, Coordination> s;
|
||||
|
||||
public:
|
||||
explicit replay(Coordination cn, composite_subscription cs = composite_subscription())
|
||||
: s(count_type(), period_type(), cn, cs, composite_subscription{})
|
||||
{
|
||||
}
|
||||
|
||||
replay(std::size_t count, Coordination cn, composite_subscription cs = composite_subscription())
|
||||
: s(count_type(std::move(count)), period_type(), cn, cs, composite_subscription{})
|
||||
{
|
||||
}
|
||||
|
||||
replay(rxsc::scheduler::clock_type::duration period, Coordination cn, composite_subscription cs = composite_subscription())
|
||||
: s(count_type(), period_type(period), cn, cs, composite_subscription{})
|
||||
{
|
||||
}
|
||||
|
||||
replay(std::size_t count, rxsc::scheduler::clock_type::duration period, Coordination cn, composite_subscription cs = composite_subscription())
|
||||
: s(count_type(count), period_type(period), cn, cs, composite_subscription{})
|
||||
{
|
||||
}
|
||||
|
||||
bool has_observers() const {
|
||||
return s.has_observers();
|
||||
}
|
||||
|
||||
std::list<T> get_values() const {
|
||||
return s.get_values();
|
||||
}
|
||||
|
||||
subscriber<T> get_subscriber() const {
|
||||
return s.get_subscriber();
|
||||
}
|
||||
|
||||
observable<T> get_observable() const {
|
||||
auto keepAlive = s;
|
||||
auto observable = make_observable_dynamic<T>([keepAlive](subscriber<T> o){
|
||||
for (auto&& value: keepAlive.get_values()) {
|
||||
o.on_next(value);
|
||||
}
|
||||
keepAlive.add(keepAlive.get_subscriber(), std::move(o));
|
||||
});
|
||||
return s.get_coordinator().in(observable);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
277
3party/rxcpp/subjects/rx-subject.hpp
Normal file
277
3party/rxcpp/subjects/rx-subject.hpp
Normal file
@@ -0,0 +1,277 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_RX_SUBJECT_HPP)
|
||||
#define RXCPP_RX_SUBJECT_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace subjects {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class multicast_observer
|
||||
{
|
||||
typedef subscriber<T> observer_type;
|
||||
typedef std::vector<observer_type> list_type;
|
||||
|
||||
struct mode
|
||||
{
|
||||
enum type {
|
||||
Invalid = 0,
|
||||
Casting,
|
||||
Disposed,
|
||||
Completed,
|
||||
Errored
|
||||
};
|
||||
};
|
||||
|
||||
struct state_type
|
||||
: public std::enable_shared_from_this<state_type>
|
||||
{
|
||||
explicit state_type(composite_subscription cs)
|
||||
: current(mode::Casting)
|
||||
, lifetime(cs)
|
||||
{
|
||||
}
|
||||
std::mutex lock;
|
||||
typename mode::type current;
|
||||
rxu::error_ptr error;
|
||||
composite_subscription lifetime;
|
||||
};
|
||||
|
||||
struct completer_type
|
||||
: public std::enable_shared_from_this<completer_type>
|
||||
{
|
||||
~completer_type()
|
||||
{
|
||||
}
|
||||
completer_type(std::shared_ptr<state_type> s, const std::shared_ptr<completer_type>& old, observer_type o)
|
||||
: state(s)
|
||||
{
|
||||
retain(old);
|
||||
observers.push_back(o);
|
||||
}
|
||||
completer_type(std::shared_ptr<state_type> s, const std::shared_ptr<completer_type>& old)
|
||||
: state(s)
|
||||
{
|
||||
retain(old);
|
||||
}
|
||||
void retain(const std::shared_ptr<completer_type>& old) {
|
||||
if (old) {
|
||||
observers.reserve(old->observers.size() + 1);
|
||||
std::copy_if(
|
||||
old->observers.begin(), old->observers.end(),
|
||||
std::inserter(observers, observers.end()),
|
||||
[](const observer_type& o){
|
||||
return o.is_subscribed();
|
||||
});
|
||||
}
|
||||
}
|
||||
std::shared_ptr<state_type> state;
|
||||
list_type observers;
|
||||
};
|
||||
|
||||
// this type prevents a circular ref between state and completer
|
||||
struct binder_type
|
||||
: public std::enable_shared_from_this<binder_type>
|
||||
{
|
||||
explicit binder_type(composite_subscription cs)
|
||||
: state(std::make_shared<state_type>(cs))
|
||||
, id(trace_id::make_next_id_subscriber())
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<state_type> state;
|
||||
|
||||
trace_id id;
|
||||
|
||||
// used to avoid taking lock in on_next
|
||||
mutable std::weak_ptr<completer_type> current_completer;
|
||||
|
||||
// must only be accessed under state->lock
|
||||
mutable std::shared_ptr<completer_type> completer;
|
||||
};
|
||||
|
||||
std::shared_ptr<binder_type> b;
|
||||
|
||||
public:
|
||||
typedef subscriber<T, observer<T, detail::multicast_observer<T>>> input_subscriber_type;
|
||||
|
||||
explicit multicast_observer(composite_subscription cs)
|
||||
: b(std::make_shared<binder_type>(cs))
|
||||
{
|
||||
std::weak_ptr<binder_type> binder = b;
|
||||
b->state->lifetime.add([binder](){
|
||||
auto b = binder.lock();
|
||||
if (b && b->state->current == mode::Casting){
|
||||
b->state->current = mode::Disposed;
|
||||
b->current_completer.reset();
|
||||
b->completer.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
trace_id get_id() const {
|
||||
return b->id;
|
||||
}
|
||||
composite_subscription get_subscription() const {
|
||||
return b->state->lifetime;
|
||||
}
|
||||
input_subscriber_type get_subscriber() const {
|
||||
return make_subscriber<T>(get_id(), get_subscription(), observer<T, detail::multicast_observer<T>>(*this));
|
||||
}
|
||||
bool has_observers() const {
|
||||
std::unique_lock<std::mutex> guard(b->state->lock);
|
||||
return b->completer && !b->completer->observers.empty();
|
||||
}
|
||||
template<class SubscriberFrom>
|
||||
void add(const SubscriberFrom& sf, observer_type o) const {
|
||||
trace_activity().connect(sf, o);
|
||||
std::unique_lock<std::mutex> guard(b->state->lock);
|
||||
switch (b->state->current) {
|
||||
case mode::Casting:
|
||||
{
|
||||
if (o.is_subscribed()) {
|
||||
std::weak_ptr<binder_type> binder = b;
|
||||
o.add([=](){
|
||||
auto b = binder.lock();
|
||||
if (b) {
|
||||
std::unique_lock<std::mutex> guard(b->state->lock);
|
||||
b->completer = std::make_shared<completer_type>(b->state, b->completer);
|
||||
}
|
||||
});
|
||||
b->completer = std::make_shared<completer_type>(b->state, b->completer, o);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mode::Completed:
|
||||
{
|
||||
guard.unlock();
|
||||
o.on_completed();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case mode::Errored:
|
||||
{
|
||||
auto e = b->state->error;
|
||||
guard.unlock();
|
||||
o.on_error(e);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case mode::Disposed:
|
||||
{
|
||||
guard.unlock();
|
||||
o.unsubscribe();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
template<class V>
|
||||
void on_next(V v) const {
|
||||
auto current_completer = b->current_completer.lock();
|
||||
if (!current_completer) {
|
||||
std::unique_lock<std::mutex> guard(b->state->lock);
|
||||
b->current_completer = b->completer;
|
||||
current_completer = b->current_completer.lock();
|
||||
}
|
||||
if (!current_completer || current_completer->observers.empty()) {
|
||||
return;
|
||||
}
|
||||
for (auto& o : current_completer->observers) {
|
||||
if (o.is_subscribed()) {
|
||||
o.on_next(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
void on_error(rxu::error_ptr e) const {
|
||||
std::unique_lock<std::mutex> guard(b->state->lock);
|
||||
if (b->state->current == mode::Casting) {
|
||||
b->state->error = e;
|
||||
b->state->current = mode::Errored;
|
||||
auto s = b->state->lifetime;
|
||||
auto c = std::move(b->completer);
|
||||
b->current_completer.reset();
|
||||
guard.unlock();
|
||||
if (c) {
|
||||
for (auto& o : c->observers) {
|
||||
if (o.is_subscribed()) {
|
||||
o.on_error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
s.unsubscribe();
|
||||
}
|
||||
}
|
||||
void on_completed() const {
|
||||
std::unique_lock<std::mutex> guard(b->state->lock);
|
||||
if (b->state->current == mode::Casting) {
|
||||
b->state->current = mode::Completed;
|
||||
auto s = b->state->lifetime;
|
||||
auto c = std::move(b->completer);
|
||||
b->current_completer.reset();
|
||||
guard.unlock();
|
||||
if (c) {
|
||||
for (auto& o : c->observers) {
|
||||
if (o.is_subscribed()) {
|
||||
o.on_completed();
|
||||
}
|
||||
}
|
||||
}
|
||||
s.unsubscribe();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class subject
|
||||
{
|
||||
detail::multicast_observer<T> s;
|
||||
|
||||
public:
|
||||
typedef subscriber<T, observer<T, detail::multicast_observer<T>>> subscriber_type;
|
||||
typedef observable<T> observable_type;
|
||||
subject()
|
||||
: s(composite_subscription())
|
||||
{
|
||||
}
|
||||
explicit subject(composite_subscription cs)
|
||||
: s(cs)
|
||||
{
|
||||
}
|
||||
|
||||
bool has_observers() const {
|
||||
return s.has_observers();
|
||||
}
|
||||
|
||||
composite_subscription get_subscription() const {
|
||||
return s.get_subscription();
|
||||
}
|
||||
|
||||
subscriber_type get_subscriber() const {
|
||||
return s.get_subscriber();
|
||||
}
|
||||
|
||||
observable<T> get_observable() const {
|
||||
auto keepAlive = s;
|
||||
return make_observable_dynamic<T>([=](subscriber<T> o){
|
||||
keepAlive.add(keepAlive.get_subscriber(), std::move(o));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
263
3party/rxcpp/subjects/rx-synchronize.hpp
Normal file
263
3party/rxcpp/subjects/rx-synchronize.hpp
Normal file
@@ -0,0 +1,263 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_RX_SYNCHRONIZE_HPP)
|
||||
#define RXCPP_RX_SYNCHRONIZE_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace subjects {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class Coordination>
|
||||
class synchronize_observer : public detail::multicast_observer<T>
|
||||
{
|
||||
typedef synchronize_observer<T, Coordination> this_type;
|
||||
typedef detail::multicast_observer<T> base_type;
|
||||
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
typedef typename coordinator_type::template get<subscriber<T>>::type output_type;
|
||||
|
||||
struct synchronize_observer_state : public std::enable_shared_from_this<synchronize_observer_state>
|
||||
{
|
||||
typedef rxn::notification<T> notification_type;
|
||||
typedef typename notification_type::type base_notification_type;
|
||||
typedef std::deque<base_notification_type> queue_type;
|
||||
|
||||
struct mode
|
||||
{
|
||||
enum type {
|
||||
Invalid = 0,
|
||||
Processing,
|
||||
Empty,
|
||||
Disposed
|
||||
};
|
||||
};
|
||||
|
||||
mutable std::mutex lock;
|
||||
mutable std::condition_variable wake;
|
||||
mutable queue_type fill_queue;
|
||||
composite_subscription lifetime;
|
||||
mutable typename mode::type current;
|
||||
coordinator_type coordinator;
|
||||
output_type destination;
|
||||
|
||||
void ensure_processing(std::unique_lock<std::mutex>& guard) const {
|
||||
if (!guard.owns_lock()) {
|
||||
std::terminate();
|
||||
}
|
||||
if (current == mode::Empty) {
|
||||
current = mode::Processing;
|
||||
auto keepAlive = this->shared_from_this();
|
||||
|
||||
auto drain_queue = [keepAlive, this](const rxsc::schedulable& self){
|
||||
RXCPP_TRY {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
if (!destination.is_subscribed()) {
|
||||
current = mode::Disposed;
|
||||
fill_queue.clear();
|
||||
guard.unlock();
|
||||
lifetime.unsubscribe();
|
||||
return;
|
||||
}
|
||||
if (fill_queue.empty()) {
|
||||
current = mode::Empty;
|
||||
return;
|
||||
}
|
||||
auto notification = std::move(fill_queue.front());
|
||||
fill_queue.pop_front();
|
||||
guard.unlock();
|
||||
notification->accept(destination);
|
||||
self();
|
||||
} RXCPP_CATCH(...) {
|
||||
destination.on_error(rxu::current_exception());
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
current = mode::Empty;
|
||||
}
|
||||
};
|
||||
|
||||
auto selectedDrain = on_exception(
|
||||
[&](){return coordinator.act(drain_queue);},
|
||||
destination);
|
||||
if (selectedDrain.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto processor = coordinator.get_worker();
|
||||
guard.unlock();
|
||||
processor.schedule(lifetime, selectedDrain.get());
|
||||
}
|
||||
}
|
||||
|
||||
synchronize_observer_state(coordinator_type coor, composite_subscription cs, output_type scbr)
|
||||
: lifetime(std::move(cs))
|
||||
, current(mode::Empty)
|
||||
, coordinator(std::move(coor))
|
||||
, destination(std::move(scbr))
|
||||
{
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void on_next(V v) const {
|
||||
if (lifetime.is_subscribed()) {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
fill_queue.push_back(notification_type::on_next(std::move(v)));
|
||||
ensure_processing(guard);
|
||||
}
|
||||
wake.notify_one();
|
||||
}
|
||||
void on_error(rxu::error_ptr e) const {
|
||||
if (lifetime.is_subscribed()) {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
fill_queue.push_back(notification_type::on_error(e));
|
||||
ensure_processing(guard);
|
||||
}
|
||||
wake.notify_one();
|
||||
}
|
||||
void on_completed() const {
|
||||
if (lifetime.is_subscribed()) {
|
||||
std::unique_lock<std::mutex> guard(lock);
|
||||
fill_queue.push_back(notification_type::on_completed());
|
||||
ensure_processing(guard);
|
||||
}
|
||||
wake.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<synchronize_observer_state> state;
|
||||
|
||||
public:
|
||||
synchronize_observer(coordination_type cn, composite_subscription dl, composite_subscription il)
|
||||
: base_type(dl)
|
||||
{
|
||||
auto o = make_subscriber<T>(dl, make_observer_dynamic<T>( *static_cast<base_type*>(this) ));
|
||||
|
||||
// creates a worker whose lifetime is the same as the destination subscription
|
||||
auto coordinator = cn.create_coordinator(dl);
|
||||
|
||||
state = std::make_shared<synchronize_observer_state>(std::move(coordinator), std::move(il), std::move(o));
|
||||
}
|
||||
|
||||
subscriber<T> get_subscriber() const {
|
||||
return make_subscriber<T>(this->get_id(), state->lifetime, observer<T, detail::synchronize_observer<T, Coordination>>(*this)).as_dynamic();
|
||||
}
|
||||
|
||||
template<class V>
|
||||
void on_next(V v) const {
|
||||
state->on_next(std::move(v));
|
||||
}
|
||||
void on_error(rxu::error_ptr e) const {
|
||||
state->on_error(e);
|
||||
}
|
||||
void on_completed() const {
|
||||
state->on_completed();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<class T, class Coordination>
|
||||
class synchronize
|
||||
{
|
||||
detail::synchronize_observer<T, Coordination> s;
|
||||
|
||||
public:
|
||||
explicit synchronize(Coordination cn, composite_subscription cs = composite_subscription())
|
||||
: s(std::move(cn), std::move(cs), composite_subscription())
|
||||
{
|
||||
}
|
||||
|
||||
bool has_observers() const {
|
||||
return s.has_observers();
|
||||
}
|
||||
|
||||
subscriber<T> get_subscriber() const {
|
||||
return s.get_subscriber();
|
||||
}
|
||||
|
||||
observable<T> get_observable() const {
|
||||
auto keepAlive = s;
|
||||
return make_observable_dynamic<T>([=](subscriber<T> o){
|
||||
keepAlive.add(keepAlive.get_subscriber(), std::move(o));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class synchronize_in_one_worker : public coordination_base
|
||||
{
|
||||
rxsc::scheduler factory;
|
||||
|
||||
class input_type
|
||||
{
|
||||
rxsc::worker controller;
|
||||
rxsc::scheduler factory;
|
||||
identity_one_worker coordination;
|
||||
public:
|
||||
explicit input_type(rxsc::worker w)
|
||||
: controller(w)
|
||||
, factory(rxsc::make_same_worker(w))
|
||||
, coordination(factory)
|
||||
{
|
||||
}
|
||||
inline rxsc::worker get_worker() const {
|
||||
return controller;
|
||||
}
|
||||
inline rxsc::scheduler get_scheduler() const {
|
||||
return factory;
|
||||
}
|
||||
inline rxsc::scheduler::clock_type::time_point now() const {
|
||||
return factory.now();
|
||||
}
|
||||
template<class Observable>
|
||||
auto in(Observable o) const
|
||||
-> decltype(o.publish_synchronized(coordination).ref_count()) {
|
||||
return o.publish_synchronized(coordination).ref_count();
|
||||
}
|
||||
template<class Subscriber>
|
||||
auto out(Subscriber s) const
|
||||
-> Subscriber {
|
||||
return s;
|
||||
}
|
||||
template<class F>
|
||||
auto act(F f) const
|
||||
-> F {
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
explicit synchronize_in_one_worker(rxsc::scheduler sc) : factory(sc) {}
|
||||
|
||||
typedef coordinator<input_type> coordinator_type;
|
||||
|
||||
inline rxsc::scheduler::clock_type::time_point now() const {
|
||||
return factory.now();
|
||||
}
|
||||
|
||||
inline coordinator_type create_coordinator(composite_subscription cs = composite_subscription()) const {
|
||||
auto w = factory.create_worker(std::move(cs));
|
||||
return coordinator_type(input_type(std::move(w)));
|
||||
}
|
||||
};
|
||||
|
||||
inline synchronize_in_one_worker synchronize_event_loop() {
|
||||
static synchronize_in_one_worker r(rxsc::make_event_loop());
|
||||
return r;
|
||||
}
|
||||
|
||||
inline synchronize_in_one_worker synchronize_new_thread() {
|
||||
static synchronize_in_one_worker r(rxsc::make_new_thread());
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user