feat add rxcpp
This commit is contained in:
92
3party/rxcpp/sources/rx-create.hpp
Normal file
92
3party/rxcpp/sources/rx-create.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_CREATE_HPP)
|
||||
#define RXCPP_SOURCES_RX_CREATE_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-create.hpp
|
||||
|
||||
\brief Returns an observable that executes the specified function when a subscriber subscribes to it.
|
||||
|
||||
\tparam T the type of the items that this observable emits
|
||||
\tparam OnSubscribe the type of OnSubscribe handler function
|
||||
|
||||
\param os OnSubscribe event handler
|
||||
|
||||
\return Observable that executes the specified function when a Subscriber subscribes to it.
|
||||
|
||||
\sample
|
||||
\snippet create.cpp Create sample
|
||||
\snippet output.txt Create sample
|
||||
|
||||
\warning
|
||||
It is good practice to check the observer's is_subscribed state from within the function you pass to create
|
||||
so that your observable can stop emitting items or doing expensive calculations when there is no longer an interested observer.
|
||||
|
||||
\badcode
|
||||
\snippet create.cpp Create bad code
|
||||
\snippet output.txt Create bad code
|
||||
|
||||
\goodcode
|
||||
\snippet create.cpp Create good code
|
||||
\snippet output.txt Create good code
|
||||
|
||||
\warning
|
||||
It is good practice to use operators like observable::take to control lifetime rather than use the subscription explicitly.
|
||||
|
||||
\goodcode
|
||||
\snippet create.cpp Create great code
|
||||
\snippet output.txt Create great code
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class OnSubscribe>
|
||||
struct create : public source_base<T>
|
||||
{
|
||||
typedef create<T, OnSubscribe> this_type;
|
||||
|
||||
typedef rxu::decay_t<OnSubscribe> on_subscribe_type;
|
||||
|
||||
on_subscribe_type on_subscribe_function;
|
||||
|
||||
create(on_subscribe_type os)
|
||||
: on_subscribe_function(std::move(os))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
|
||||
on_exception(
|
||||
[&](){
|
||||
this->on_subscribe_function(o);
|
||||
return true;
|
||||
},
|
||||
o);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-create.hpp
|
||||
*/
|
||||
template<class T, class OnSubscribe>
|
||||
auto create(OnSubscribe os)
|
||||
-> observable<T, detail::create<T, OnSubscribe>> {
|
||||
return observable<T, detail::create<T, OnSubscribe>>(
|
||||
detail::create<T, OnSubscribe>(std::move(os)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
83
3party/rxcpp/sources/rx-defer.hpp
Normal file
83
3party/rxcpp/sources/rx-defer.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_DEFER_HPP)
|
||||
#define RXCPP_SOURCES_RX_DEFER_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-defer.hpp
|
||||
|
||||
\brief Returns an observable that calls the specified observable factory to create an observable for each new observer that subscribes.
|
||||
|
||||
\tparam ObservableFactory the type of the observable factory
|
||||
|
||||
\param of the observable factory function to invoke for each observer that subscribes to the resulting observable
|
||||
|
||||
\return observable whose observers' subscriptions trigger an invocation of the given observable factory function
|
||||
|
||||
\sample
|
||||
\snippet defer.cpp defer sample
|
||||
\snippet output.txt defer sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ObservableFactory>
|
||||
struct defer_traits
|
||||
{
|
||||
typedef rxu::decay_t<ObservableFactory> observable_factory_type;
|
||||
typedef decltype((*(observable_factory_type*)nullptr)()) collection_type;
|
||||
typedef typename collection_type::value_type value_type;
|
||||
};
|
||||
|
||||
template<class ObservableFactory>
|
||||
struct defer : public source_base<rxu::value_type_t<defer_traits<ObservableFactory>>>
|
||||
{
|
||||
typedef defer<ObservableFactory> this_type;
|
||||
typedef defer_traits<ObservableFactory> traits;
|
||||
|
||||
typedef typename traits::observable_factory_type observable_factory_type;
|
||||
typedef typename traits::collection_type collection_type;
|
||||
|
||||
observable_factory_type observable_factory;
|
||||
|
||||
defer(observable_factory_type of)
|
||||
: observable_factory(std::move(of))
|
||||
{
|
||||
}
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
|
||||
auto selectedCollection = on_exception(
|
||||
[this](){return this->observable_factory();},
|
||||
o);
|
||||
if (selectedCollection.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectedCollection->subscribe(o);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-defer.hpp
|
||||
*/
|
||||
template<class ObservableFactory>
|
||||
auto defer(ObservableFactory of)
|
||||
-> observable<rxu::value_type_t<detail::defer_traits<ObservableFactory>>, detail::defer<ObservableFactory>> {
|
||||
return observable<rxu::value_type_t<detail::defer_traits<ObservableFactory>>, detail::defer<ObservableFactory>>(
|
||||
detail::defer<ObservableFactory>(std::move(of)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
53
3party/rxcpp/sources/rx-empty.hpp
Normal file
53
3party/rxcpp/sources/rx-empty.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_EMPTY_HPP)
|
||||
#define RXCPP_SOURCES_RX_EMPTY_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-empty.hpp
|
||||
|
||||
\brief Returns an observable that sends no items to observer and immediately completes, on the specified scheduler.
|
||||
|
||||
\tparam T the type of (not) emitted items
|
||||
\tparam Coordination the type of the scheduler (optional)
|
||||
|
||||
\param cn the scheduler to use for scheduling the items (optional)
|
||||
|
||||
\return Observable that sends no items to observer and immediately completes.
|
||||
|
||||
\sample
|
||||
\snippet empty.cpp empty sample
|
||||
\snippet output.txt empty sample
|
||||
|
||||
\sample
|
||||
\snippet empty.cpp threaded empty sample
|
||||
\snippet output.txt threaded empty sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
/*! @copydoc rx-empty.hpp
|
||||
*/
|
||||
template<class T>
|
||||
auto empty()
|
||||
-> decltype(from<T>()) {
|
||||
return from<T>();
|
||||
}
|
||||
/*! @copydoc rx-empty.hpp
|
||||
*/
|
||||
template<class T, class Coordination>
|
||||
auto empty(Coordination cn)
|
||||
-> decltype(from<T>(std::move(cn))) {
|
||||
return from<T>(std::move(cn));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
133
3party/rxcpp/sources/rx-error.hpp
Normal file
133
3party/rxcpp/sources/rx-error.hpp
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_ERROR_HPP)
|
||||
#define RXCPP_SOURCES_RX_ERROR_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-error.hpp
|
||||
|
||||
\brief Returns an observable that sends no items to observer and immediately generates an error, on the specified scheduler.
|
||||
|
||||
\tparam T the type of (not) emitted items
|
||||
\tparam Exception the type of the error
|
||||
\tparam Coordination the type of the scheduler (optional)
|
||||
|
||||
\param e the error to be passed to observers
|
||||
\param cn the scheduler to use for scheduling the items (optional)
|
||||
|
||||
\return Observable that sends no items to observer and immediately generates an error.
|
||||
|
||||
\sample
|
||||
\snippet error.cpp error sample
|
||||
\snippet output.txt error sample
|
||||
|
||||
\sample
|
||||
\snippet error.cpp threaded error sample
|
||||
\snippet output.txt threaded error sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class Coordination>
|
||||
struct error : public source_base<T>
|
||||
{
|
||||
typedef error<T, Coordination> this_type;
|
||||
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
|
||||
struct error_initial_type
|
||||
{
|
||||
error_initial_type(rxu::error_ptr e, coordination_type cn)
|
||||
: exception(e)
|
||||
, coordination(std::move(cn))
|
||||
{
|
||||
}
|
||||
rxu::error_ptr exception;
|
||||
coordination_type coordination;
|
||||
};
|
||||
error_initial_type initial;
|
||||
|
||||
error(rxu::error_ptr e, coordination_type cn)
|
||||
: initial(e, std::move(cn))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
|
||||
// creates a worker whose lifetime is the same as this subscription
|
||||
auto coordinator = initial.coordination.create_coordinator(o.get_subscription());
|
||||
auto controller = coordinator.get_worker();
|
||||
auto exception = initial.exception;
|
||||
|
||||
auto producer = [=](const rxsc::schedulable&){
|
||||
auto& dest = o;
|
||||
if (!dest.is_subscribed()) {
|
||||
// terminate loop
|
||||
return;
|
||||
}
|
||||
|
||||
dest.on_error(exception);
|
||||
// o is unsubscribed
|
||||
};
|
||||
auto selectedProducer = on_exception(
|
||||
[&](){return coordinator.act(producer);},
|
||||
o);
|
||||
if (selectedProducer.empty()) {
|
||||
return;
|
||||
}
|
||||
controller.schedule(selectedProducer.get());
|
||||
}
|
||||
};
|
||||
|
||||
struct throw_ptr_tag{};
|
||||
struct throw_instance_tag{};
|
||||
|
||||
template <class T, class Coordination>
|
||||
auto make_error(throw_ptr_tag&&, rxu::error_ptr exception, Coordination cn)
|
||||
-> observable<T, error<T, Coordination>> {
|
||||
return observable<T, error<T, Coordination>>(error<T, Coordination>(std::move(exception), std::move(cn)));
|
||||
}
|
||||
|
||||
template <class T, class E, class Coordination>
|
||||
auto make_error(throw_instance_tag&&, E e, Coordination cn)
|
||||
-> observable<T, error<T, Coordination>> {
|
||||
rxu::error_ptr ep = rxu::make_error_ptr(e);
|
||||
return observable<T, error<T, Coordination>>(error<T, Coordination>(std::move(ep), std::move(cn)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace sources {
|
||||
|
||||
/*! @copydoc rx-error.hpp
|
||||
*/
|
||||
template<class T, class E>
|
||||
auto error(E e)
|
||||
-> decltype(detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), identity_immediate())) {
|
||||
return detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), identity_immediate());
|
||||
}
|
||||
/*! @copydoc rx-error.hpp
|
||||
*/
|
||||
template<class T, class E, class Coordination>
|
||||
auto error(E e, Coordination cn)
|
||||
-> decltype(detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), std::move(cn))) {
|
||||
return detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), std::move(cn));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
154
3party/rxcpp/sources/rx-interval.hpp
Normal file
154
3party/rxcpp/sources/rx-interval.hpp
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_INTERVAL_HPP)
|
||||
#define RXCPP_SOURCES_RX_INTERVAL_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-interval.hpp
|
||||
|
||||
\brief Returns an observable that emits a sequential integer every specified time interval, on the specified scheduler.
|
||||
|
||||
\tparam Coordination the type of the scheduler (optional)
|
||||
|
||||
\param period period between emitted values
|
||||
\param cn the scheduler to use for scheduling the items (optional)
|
||||
|
||||
\return Observable that sends a sequential integer each time interval
|
||||
|
||||
\sample
|
||||
\snippet interval.cpp interval sample
|
||||
\snippet output.txt interval sample
|
||||
|
||||
\sample
|
||||
\snippet interval.cpp immediate interval sample
|
||||
\snippet output.txt immediate interval sample
|
||||
|
||||
\sample
|
||||
\snippet interval.cpp threaded interval sample
|
||||
\snippet output.txt threaded interval sample
|
||||
|
||||
\sample
|
||||
\snippet interval.cpp threaded immediate interval sample
|
||||
\snippet output.txt threaded immediate interval sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Coordination>
|
||||
struct interval : public source_base<long>
|
||||
{
|
||||
typedef interval<Coordination> this_type;
|
||||
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
|
||||
struct interval_initial_type
|
||||
{
|
||||
interval_initial_type(rxsc::scheduler::clock_type::time_point i, rxsc::scheduler::clock_type::duration p, coordination_type cn)
|
||||
: initial(i)
|
||||
, period(p)
|
||||
, coordination(std::move(cn))
|
||||
{
|
||||
}
|
||||
rxsc::scheduler::clock_type::time_point initial;
|
||||
rxsc::scheduler::clock_type::duration period;
|
||||
coordination_type coordination;
|
||||
};
|
||||
interval_initial_type initial;
|
||||
|
||||
interval(rxsc::scheduler::clock_type::time_point i, rxsc::scheduler::clock_type::duration p, coordination_type cn)
|
||||
: initial(i, p, std::move(cn))
|
||||
{
|
||||
}
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
static_assert(is_subscriber<Subscriber>::value, "subscribe must be passed a subscriber");
|
||||
|
||||
// creates a worker whose lifetime is the same as this subscription
|
||||
auto coordinator = initial.coordination.create_coordinator(o.get_subscription());
|
||||
|
||||
auto controller = coordinator.get_worker();
|
||||
|
||||
auto counter = std::make_shared<long>(0);
|
||||
|
||||
auto producer = [o, counter](const rxsc::schedulable&) {
|
||||
// send next value
|
||||
o.on_next(++(*counter));
|
||||
};
|
||||
|
||||
auto selectedProducer = on_exception(
|
||||
[&](){return coordinator.act(producer);},
|
||||
o);
|
||||
if (selectedProducer.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.schedule_periodically(initial.initial, initial.period, selectedProducer.get());
|
||||
}
|
||||
};
|
||||
|
||||
template<class Duration, class Coordination>
|
||||
struct defer_interval : public defer_observable<
|
||||
rxu::all_true<
|
||||
std::is_convertible<Duration, rxsc::scheduler::clock_type::duration>::value,
|
||||
is_coordination<Coordination>::value>,
|
||||
void,
|
||||
interval, Coordination>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*! @copydoc rx-interval.hpp
|
||||
*/
|
||||
template<class Duration>
|
||||
auto interval(Duration period)
|
||||
-> typename std::enable_if<
|
||||
detail::defer_interval<Duration, identity_one_worker>::value,
|
||||
typename detail::defer_interval<Duration, identity_one_worker>::observable_type>::type {
|
||||
return detail::defer_interval<Duration, identity_one_worker>::make(identity_current_thread().now(), period, identity_current_thread());
|
||||
}
|
||||
|
||||
/*! @copydoc rx-interval.hpp
|
||||
*/
|
||||
template<class Coordination>
|
||||
auto interval(rxsc::scheduler::clock_type::duration period, Coordination cn)
|
||||
-> typename std::enable_if<
|
||||
detail::defer_interval<rxsc::scheduler::clock_type::duration, Coordination>::value,
|
||||
typename detail::defer_interval<rxsc::scheduler::clock_type::duration, Coordination>::observable_type>::type {
|
||||
return detail::defer_interval<rxsc::scheduler::clock_type::duration, Coordination>::make(cn.now(), period, std::move(cn));
|
||||
}
|
||||
|
||||
/*! @copydoc rx-interval.hpp
|
||||
*/
|
||||
template<class Duration>
|
||||
auto interval(rxsc::scheduler::clock_type::time_point when, Duration period)
|
||||
-> typename std::enable_if<
|
||||
detail::defer_interval<Duration, identity_one_worker>::value,
|
||||
typename detail::defer_interval<Duration, identity_one_worker>::observable_type>::type {
|
||||
return detail::defer_interval<Duration, identity_one_worker>::make(when, period, identity_current_thread());
|
||||
}
|
||||
|
||||
/*! @copydoc rx-interval.hpp
|
||||
*/
|
||||
template<class Coordination>
|
||||
auto interval(rxsc::scheduler::clock_type::time_point when, rxsc::scheduler::clock_type::duration period, Coordination cn)
|
||||
-> typename std::enable_if<
|
||||
detail::defer_interval<rxsc::scheduler::clock_type::duration, Coordination>::value,
|
||||
typename detail::defer_interval<rxsc::scheduler::clock_type::duration, Coordination>::observable_type>::type {
|
||||
return detail::defer_interval<rxsc::scheduler::clock_type::duration, Coordination>::make(when, period, std::move(cn));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
325
3party/rxcpp/sources/rx-iterate.hpp
Normal file
325
3party/rxcpp/sources/rx-iterate.hpp
Normal file
@ -0,0 +1,325 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_ITERATE_HPP)
|
||||
#define RXCPP_SOURCES_RX_ITERATE_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-iterate.hpp
|
||||
|
||||
\brief Returns an observable that sends each value in the collection, on the specified scheduler.
|
||||
|
||||
\tparam Collection the type of the collection of values that this observable emits
|
||||
\tparam Coordination the type of the scheduler (optional)
|
||||
|
||||
\param c collection containing values to send
|
||||
\param cn the scheduler to use for scheduling the items (optional)
|
||||
|
||||
\return Observable that sends each value in the collection.
|
||||
|
||||
\sample
|
||||
\snippet iterate.cpp iterate sample
|
||||
\snippet output.txt iterate sample
|
||||
|
||||
\sample
|
||||
\snippet iterate.cpp threaded iterate sample
|
||||
\snippet output.txt threaded iterate sample
|
||||
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Collection>
|
||||
struct is_iterable
|
||||
{
|
||||
typedef rxu::decay_t<Collection> collection_type;
|
||||
|
||||
struct not_void {};
|
||||
template<class CC>
|
||||
static auto check(int) -> decltype(std::begin(*(CC*)nullptr));
|
||||
template<class CC>
|
||||
static not_void check(...);
|
||||
|
||||
static const bool value = !std::is_same<decltype(check<collection_type>(0)), not_void>::value;
|
||||
};
|
||||
|
||||
template<class Collection>
|
||||
struct iterate_traits
|
||||
{
|
||||
typedef rxu::decay_t<Collection> collection_type;
|
||||
typedef rxu::decay_t<decltype(std::begin(*(collection_type*)nullptr))> iterator_type;
|
||||
typedef rxu::value_type_t<std::iterator_traits<iterator_type>> value_type;
|
||||
};
|
||||
|
||||
template<class Collection, class Coordination>
|
||||
struct iterate : public source_base<rxu::value_type_t<iterate_traits<Collection>>>
|
||||
{
|
||||
typedef iterate<Collection, Coordination> this_type;
|
||||
typedef iterate_traits<Collection> traits;
|
||||
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
|
||||
typedef typename traits::collection_type collection_type;
|
||||
typedef typename traits::iterator_type iterator_type;
|
||||
|
||||
struct iterate_initial_type
|
||||
{
|
||||
iterate_initial_type(collection_type c, coordination_type cn)
|
||||
: collection(std::move(c))
|
||||
, coordination(std::move(cn))
|
||||
{
|
||||
}
|
||||
collection_type collection;
|
||||
coordination_type coordination;
|
||||
};
|
||||
iterate_initial_type initial;
|
||||
|
||||
iterate(collection_type c, coordination_type cn)
|
||||
: initial(std::move(c), std::move(cn))
|
||||
{
|
||||
}
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
static_assert(is_subscriber<Subscriber>::value, "subscribe must be passed a subscriber");
|
||||
|
||||
typedef typename coordinator_type::template get<Subscriber>::type output_type;
|
||||
|
||||
struct iterate_state_type
|
||||
: public iterate_initial_type
|
||||
{
|
||||
iterate_state_type(const iterate_initial_type& i, output_type o)
|
||||
: iterate_initial_type(i)
|
||||
, cursor(std::begin(iterate_initial_type::collection))
|
||||
, end(std::end(iterate_initial_type::collection))
|
||||
, out(std::move(o))
|
||||
{
|
||||
}
|
||||
iterate_state_type(const iterate_state_type& o)
|
||||
: iterate_initial_type(o)
|
||||
, cursor(std::begin(iterate_initial_type::collection))
|
||||
, end(std::end(iterate_initial_type::collection))
|
||||
, out(std::move(o.out)) // since lambda capture does not yet support move
|
||||
{
|
||||
}
|
||||
mutable iterator_type cursor;
|
||||
iterator_type end;
|
||||
mutable output_type out;
|
||||
};
|
||||
|
||||
// creates a worker whose lifetime is the same as this subscription
|
||||
auto coordinator = initial.coordination.create_coordinator(o.get_subscription());
|
||||
|
||||
iterate_state_type state(initial, o);
|
||||
|
||||
auto controller = coordinator.get_worker();
|
||||
|
||||
auto producer = [state](const rxsc::schedulable& self){
|
||||
if (!state.out.is_subscribed()) {
|
||||
// terminate loop
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.cursor != state.end) {
|
||||
// send next value
|
||||
state.out.on_next(*state.cursor);
|
||||
++state.cursor;
|
||||
}
|
||||
|
||||
if (state.cursor == state.end) {
|
||||
state.out.on_completed();
|
||||
// o is unsubscribed
|
||||
return;
|
||||
}
|
||||
|
||||
// tail recurse this same action to continue loop
|
||||
self();
|
||||
};
|
||||
auto selectedProducer = on_exception(
|
||||
[&](){return coordinator.act(producer);},
|
||||
o);
|
||||
if (selectedProducer.empty()) {
|
||||
return;
|
||||
}
|
||||
controller.schedule(selectedProducer.get());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-iterate.hpp
|
||||
*/
|
||||
template<class Collection>
|
||||
auto iterate(Collection c)
|
||||
-> observable<rxu::value_type_t<detail::iterate_traits<Collection>>, detail::iterate<Collection, identity_one_worker>> {
|
||||
return observable<rxu::value_type_t<detail::iterate_traits<Collection>>, detail::iterate<Collection, identity_one_worker>>(
|
||||
detail::iterate<Collection, identity_one_worker>(std::move(c), identity_immediate()));
|
||||
}
|
||||
/*! @copydoc rx-iterate.hpp
|
||||
*/
|
||||
template<class Collection, class Coordination>
|
||||
auto iterate(Collection c, Coordination cn)
|
||||
-> observable<rxu::value_type_t<detail::iterate_traits<Collection>>, detail::iterate<Collection, Coordination>> {
|
||||
return observable<rxu::value_type_t<detail::iterate_traits<Collection>>, detail::iterate<Collection, Coordination>>(
|
||||
detail::iterate<Collection, Coordination>(std::move(c), std::move(cn)));
|
||||
}
|
||||
|
||||
/*! Returns an observable that sends an empty set of values and then completes.
|
||||
|
||||
\tparam T the type of elements (not) to be sent
|
||||
|
||||
\return Observable that sends an empty set of values and then completes.
|
||||
|
||||
This is a degenerate case of rxcpp::observable<void,void>#from(Value0,ValueN...) operator.
|
||||
|
||||
\note This is a degenerate case of ```from(Value0 v0, ValueN... vn)``` operator.
|
||||
*/
|
||||
template<class T>
|
||||
auto from()
|
||||
-> decltype(iterate(std::initializer_list<T>(), identity_immediate())) {
|
||||
return iterate(std::initializer_list<T>(), identity_immediate());
|
||||
}
|
||||
/*! Returns an observable that sends an empty set of values and then completes, on the specified scheduler.
|
||||
|
||||
\tparam T the type of elements (not) to be sent
|
||||
\tparam Coordination the type of the scheduler
|
||||
|
||||
\return Observable that sends an empty set of values and then completes.
|
||||
|
||||
\note This is a degenerate case of ```from(Coordination cn, Value0 v0, ValueN... vn)``` operator.
|
||||
*/
|
||||
template<class T, class Coordination>
|
||||
auto from(Coordination cn)
|
||||
-> typename std::enable_if<is_coordination<Coordination>::value,
|
||||
decltype( iterate(std::initializer_list<T>(), std::move(cn)))>::type {
|
||||
return iterate(std::initializer_list<T>(), std::move(cn));
|
||||
}
|
||||
/*! Returns an observable that sends each value from its arguments list.
|
||||
|
||||
\tparam Value0 ...
|
||||
\tparam ValueN the type of sending values
|
||||
|
||||
\param v0 ...
|
||||
\param vn values to send
|
||||
|
||||
\return Observable that sends each value from its arguments list.
|
||||
|
||||
\sample
|
||||
\snippet from.cpp from sample
|
||||
\snippet output.txt from sample
|
||||
|
||||
\note This operator is useful to send separated values. If they are stored as a collection, use observable<void,void>::iterate instead.
|
||||
*/
|
||||
template<class Value0, class... ValueN>
|
||||
auto from(Value0 v0, ValueN... vn)
|
||||
-> typename std::enable_if<!is_coordination<Value0>::value,
|
||||
decltype(iterate(*(std::array<Value0, sizeof...(ValueN) + 1>*)nullptr, identity_immediate()))>::type {
|
||||
std::array<Value0, sizeof...(ValueN) + 1> c{{v0, vn...}};
|
||||
return iterate(std::move(c), identity_immediate());
|
||||
}
|
||||
/*! Returns an observable that sends each value from its arguments list, on the specified scheduler.
|
||||
|
||||
\tparam Coordination the type of the scheduler
|
||||
\tparam Value0 ...
|
||||
\tparam ValueN the type of sending values
|
||||
|
||||
\param cn the scheduler to use for scheduling the items
|
||||
\param v0 ...
|
||||
\param vn values to send
|
||||
|
||||
\return Observable that sends each value from its arguments list.
|
||||
|
||||
\sample
|
||||
\snippet from.cpp threaded from sample
|
||||
\snippet output.txt threaded from sample
|
||||
|
||||
\note This operator is useful to send separated values. If they are stored as a collection, use observable<void,void>::iterate instead.
|
||||
*/
|
||||
template<class Coordination, class Value0, class... ValueN>
|
||||
auto from(Coordination cn, Value0 v0, ValueN... vn)
|
||||
-> typename std::enable_if<is_coordination<Coordination>::value,
|
||||
decltype(iterate(*(std::array<Value0, sizeof...(ValueN) + 1>*)nullptr, std::move(cn)))>::type {
|
||||
std::array<Value0, sizeof...(ValueN) + 1> c{{v0, vn...}};
|
||||
return iterate(std::move(c), std::move(cn));
|
||||
}
|
||||
|
||||
|
||||
/*! Returns an observable that sends the specified item to observer and then completes.
|
||||
|
||||
\tparam T the type of the emitted item
|
||||
|
||||
\param v the value to send
|
||||
|
||||
\return Observable that sends the specified item to observer and then completes.
|
||||
|
||||
\sample
|
||||
\snippet just.cpp just sample
|
||||
\snippet output.txt just sample
|
||||
*/
|
||||
template<class Value0>
|
||||
auto just(Value0 v0)
|
||||
-> typename std::enable_if<!is_coordination<Value0>::value,
|
||||
decltype(iterate(*(std::array<Value0, 1>*)nullptr, identity_immediate()))>::type {
|
||||
std::array<Value0, 1> c{{v0}};
|
||||
return iterate(std::move(c), identity_immediate());
|
||||
}
|
||||
/*! Returns an observable that sends the specified item to observer and then completes, on the specified scheduler.
|
||||
|
||||
\tparam T the type of the emitted item
|
||||
\tparam Coordination the type of the scheduler
|
||||
|
||||
\param v the value to send
|
||||
\param cn the scheduler to use for scheduling the items
|
||||
|
||||
\return Observable that sends the specified item to observer and then completes.
|
||||
|
||||
\sample
|
||||
\snippet just.cpp threaded just sample
|
||||
\snippet output.txt threaded just sample
|
||||
*/
|
||||
template<class Value0, class Coordination>
|
||||
auto just(Value0 v0, Coordination cn)
|
||||
-> typename std::enable_if<is_coordination<Coordination>::value,
|
||||
decltype(iterate(*(std::array<Value0, 1>*)nullptr, std::move(cn)))>::type {
|
||||
std::array<Value0, 1> c{{v0}};
|
||||
return iterate(std::move(c), std::move(cn));
|
||||
}
|
||||
|
||||
/*! Returns an observable that sends the specified values before it begins to send items emitted by the given observable.
|
||||
|
||||
\tparam Observable the type of the observable that emits values for resending
|
||||
\tparam Value0 ...
|
||||
\tparam ValueN the type of sending values
|
||||
|
||||
\param o the observable that emits values for resending
|
||||
\param v0 ...
|
||||
\param vn values to send
|
||||
|
||||
\return Observable that sends the specified values before it begins to send items emitted by the given observable.
|
||||
|
||||
\sample
|
||||
\snippet start_with.cpp full start_with sample
|
||||
\snippet output.txt full start_with sample
|
||||
|
||||
Instead of passing the observable as a parameter, you can use rxcpp::observable<T, SourceOperator>::start_with method of the existing observable:
|
||||
\snippet start_with.cpp short start_with sample
|
||||
\snippet output.txt short start_with sample
|
||||
*/
|
||||
template<class Observable, class Value0, class... ValueN>
|
||||
auto start_with(Observable o, Value0 v0, ValueN... vn)
|
||||
-> decltype(from(rxu::value_type_t<Observable>(v0), rxu::value_type_t<Observable>(vn)...).concat(o)) {
|
||||
return from(rxu::value_type_t<Observable>(v0), rxu::value_type_t<Observable>(vn)...).concat(o);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
51
3party/rxcpp/sources/rx-never.hpp
Normal file
51
3party/rxcpp/sources/rx-never.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_NEVER_HPP)
|
||||
#define RXCPP_SOURCES_RX_NEVER_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-never.hpp
|
||||
|
||||
\brief Returns an observable that never sends any items or notifications to observer.
|
||||
|
||||
\tparam T the type of (not) emitted items
|
||||
|
||||
\return Observable that never sends any items or notifications to observer.
|
||||
|
||||
\sample
|
||||
\snippet never.cpp never sample
|
||||
\snippet output.txt never sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
struct never : public source_base<T>
|
||||
{
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber) const {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-never.hpp
|
||||
*/
|
||||
template<class T>
|
||||
auto never()
|
||||
-> observable<T, detail::never<T>> {
|
||||
return observable<T, detail::never<T>>(detail::never<T>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
155
3party/rxcpp/sources/rx-range.hpp
Normal file
155
3party/rxcpp/sources/rx-range.hpp
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_RANGE_HPP)
|
||||
#define RXCPP_SOURCES_RX_RANGE_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-range.hpp
|
||||
|
||||
\brief Returns an observable that sends values in the range ```first```-```last``` by adding ```step``` to the previous value. The values are sent on the specified scheduler.
|
||||
|
||||
\tparam T the type of the values that this observable emits
|
||||
\tparam Coordination the type of the scheduler (optional)
|
||||
|
||||
\param first first value to send (optional)
|
||||
\param last last value to send (optional)
|
||||
\param step value to add to the previous value to get the next value (optional)
|
||||
\param cn the scheduler to run the generator loop on (optional)
|
||||
|
||||
\return Observable that sends values in the range ```first```-```last``` by adding ```step``` to the previous value using the specified scheduler.
|
||||
|
||||
\sample
|
||||
\snippet range.cpp threaded range sample
|
||||
\snippet output.txt threaded range sample
|
||||
|
||||
An alternative way to specify the scheduler for emitted values is to use observable::subscribe_on operator
|
||||
\snippet range.cpp subscribe_on range sample
|
||||
\snippet output.txt subscribe_on range sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T, class Coordination>
|
||||
struct range : public source_base<T>
|
||||
{
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
|
||||
struct range_state_type
|
||||
{
|
||||
range_state_type(T f, T l, std::ptrdiff_t s, coordination_type cn)
|
||||
: next(f)
|
||||
, last(l)
|
||||
, step(s)
|
||||
, coordination(std::move(cn))
|
||||
{
|
||||
}
|
||||
mutable T next;
|
||||
T last;
|
||||
std::ptrdiff_t step;
|
||||
coordination_type coordination;
|
||||
};
|
||||
range_state_type initial;
|
||||
range(T f, T l, std::ptrdiff_t s, coordination_type cn)
|
||||
: initial(f, l, s, std::move(cn))
|
||||
{
|
||||
}
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
static_assert(is_subscriber<Subscriber>::value, "subscribe must be passed a subscriber");
|
||||
|
||||
// creates a worker whose lifetime is the same as this subscription
|
||||
auto coordinator = initial.coordination.create_coordinator(o.get_subscription());
|
||||
|
||||
auto controller = coordinator.get_worker();
|
||||
|
||||
auto state = initial;
|
||||
|
||||
auto producer = [=](const rxsc::schedulable& self){
|
||||
auto& dest = o;
|
||||
if (!dest.is_subscribed()) {
|
||||
// terminate loop
|
||||
return;
|
||||
}
|
||||
|
||||
// send next value
|
||||
dest.on_next(state.next);
|
||||
if (!dest.is_subscribed()) {
|
||||
// terminate loop
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::max(state.last, state.next) - std::min(state.last, state.next) < std::abs(state.step)) {
|
||||
if (state.last != state.next) {
|
||||
dest.on_next(state.last);
|
||||
}
|
||||
dest.on_completed();
|
||||
// o is unsubscribed
|
||||
return;
|
||||
}
|
||||
state.next = static_cast<T>(state.step + state.next);
|
||||
|
||||
// tail recurse this same action to continue loop
|
||||
self();
|
||||
};
|
||||
|
||||
auto selectedProducer = on_exception(
|
||||
[&](){return coordinator.act(producer);},
|
||||
o);
|
||||
if (selectedProducer.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.schedule(selectedProducer.get());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-create.hpp
|
||||
*/
|
||||
template<class T>
|
||||
auto range(T first = 0, T last = std::numeric_limits<T>::max(), std::ptrdiff_t step = 1)
|
||||
-> observable<T, detail::range<T, identity_one_worker>> {
|
||||
return observable<T, detail::range<T, identity_one_worker>>(
|
||||
detail::range<T, identity_one_worker>(first, last, step, identity_current_thread()));
|
||||
}
|
||||
/*! @copydoc rx-create.hpp
|
||||
*/
|
||||
template<class T, class Coordination>
|
||||
auto range(T first, T last, std::ptrdiff_t step, Coordination cn)
|
||||
-> observable<T, detail::range<T, Coordination>> {
|
||||
return observable<T, detail::range<T, Coordination>>(
|
||||
detail::range<T, Coordination>(first, last, step, std::move(cn)));
|
||||
}
|
||||
/*! @copydoc rx-create.hpp
|
||||
*/
|
||||
template<class T, class Coordination>
|
||||
auto range(T first, T last, Coordination cn)
|
||||
-> typename std::enable_if<is_coordination<Coordination>::value,
|
||||
observable<T, detail::range<T, Coordination>>>::type {
|
||||
return observable<T, detail::range<T, Coordination>>(
|
||||
detail::range<T, Coordination>(first, last, 1, std::move(cn)));
|
||||
}
|
||||
/*! @copydoc rx-create.hpp
|
||||
*/
|
||||
template<class T, class Coordination>
|
||||
auto range(T first, Coordination cn)
|
||||
-> typename std::enable_if<is_coordination<Coordination>::value,
|
||||
observable<T, detail::range<T, Coordination>>>::type {
|
||||
return observable<T, detail::range<T, Coordination>>(
|
||||
detail::range<T, Coordination>(first, std::numeric_limits<T>::max(), 1, std::move(cn)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
124
3party/rxcpp/sources/rx-scope.hpp
Normal file
124
3party/rxcpp/sources/rx-scope.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_SCOPE_HPP)
|
||||
#define RXCPP_SOURCES_RX_SCOPE_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-scope.hpp
|
||||
|
||||
\brief Returns an observable that makes an observable by the specified observable factory using the resource provided by the specified resource factory for each new observer that subscribes.
|
||||
|
||||
\tparam ResourceFactory the type of the resource factory
|
||||
\tparam ObservableFactory the type of the observable factory
|
||||
|
||||
\param rf the resource factory function that resturn the rxcpp::resource that is used as a resource by the observable factory
|
||||
\param of the observable factory function to invoke for each observer that subscribes to the resulting observable
|
||||
|
||||
\return observable that makes an observable by the specified observable factory using the resource provided by the specified resource factory for each new observer that subscribes.
|
||||
|
||||
\sample
|
||||
\snippet scope.cpp scope sample
|
||||
\snippet output.txt scope sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class ResourceFactory, class ObservableFactory>
|
||||
struct scope_traits
|
||||
{
|
||||
typedef rxu::decay_t<ResourceFactory> resource_factory_type;
|
||||
typedef rxu::decay_t<ObservableFactory> observable_factory_type;
|
||||
typedef decltype((*(resource_factory_type*)nullptr)()) resource_type;
|
||||
typedef decltype((*(observable_factory_type*)nullptr)(resource_type())) collection_type;
|
||||
typedef typename collection_type::value_type value_type;
|
||||
|
||||
static_assert(is_subscription<resource_type>::value, "ResourceFactory must return a subscription");
|
||||
};
|
||||
|
||||
template<class ResourceFactory, class ObservableFactory>
|
||||
struct scope : public source_base<rxu::value_type_t<scope_traits<ResourceFactory, ObservableFactory>>>
|
||||
{
|
||||
typedef scope_traits<ResourceFactory, ObservableFactory> traits;
|
||||
typedef typename traits::resource_factory_type resource_factory_type;
|
||||
typedef typename traits::observable_factory_type observable_factory_type;
|
||||
typedef typename traits::resource_type resource_type;
|
||||
typedef typename traits::value_type value_type;
|
||||
|
||||
struct values
|
||||
{
|
||||
values(resource_factory_type rf, observable_factory_type of)
|
||||
: resource_factory(std::move(rf))
|
||||
, observable_factory(std::move(of))
|
||||
{
|
||||
}
|
||||
resource_factory_type resource_factory;
|
||||
observable_factory_type observable_factory;
|
||||
};
|
||||
values initial;
|
||||
|
||||
|
||||
scope(resource_factory_type rf, observable_factory_type of)
|
||||
: initial(std::move(rf), std::move(of))
|
||||
{
|
||||
}
|
||||
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
|
||||
struct state_type
|
||||
: public std::enable_shared_from_this<state_type>
|
||||
, public values
|
||||
{
|
||||
state_type(values i, Subscriber o)
|
||||
: values(i)
|
||||
, out(std::move(o))
|
||||
{
|
||||
}
|
||||
Subscriber out;
|
||||
rxu::detail::maybe<resource_type> resource;
|
||||
};
|
||||
|
||||
auto state = std::make_shared<state_type>(state_type(initial, std::move(o)));
|
||||
|
||||
state->resource = on_exception(
|
||||
[&](){return state->resource_factory(); },
|
||||
state->out);
|
||||
if (state->resource.empty()) {
|
||||
return;
|
||||
}
|
||||
state->out.add(state->resource->get_subscription());
|
||||
|
||||
auto selectedCollection = on_exception(
|
||||
[state](){return state->observable_factory(state->resource.get()); },
|
||||
state->out);
|
||||
if (selectedCollection.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectedCollection->subscribe(state->out);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-scope.hpp
|
||||
*/
|
||||
template<class ResourceFactory, class ObservableFactory>
|
||||
auto scope(ResourceFactory rf, ObservableFactory of)
|
||||
-> observable<rxu::value_type_t<detail::scope_traits<ResourceFactory, ObservableFactory>>, detail::scope<ResourceFactory, ObservableFactory>> {
|
||||
return observable<rxu::value_type_t<detail::scope_traits<ResourceFactory, ObservableFactory>>, detail::scope<ResourceFactory, ObservableFactory>>(
|
||||
detail::scope<ResourceFactory, ObservableFactory>(std::move(rf), std::move(of)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
135
3party/rxcpp/sources/rx-timer.hpp
Normal file
135
3party/rxcpp/sources/rx-timer.hpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(RXCPP_SOURCES_RX_TIMER_HPP)
|
||||
#define RXCPP_SOURCES_RX_TIMER_HPP
|
||||
|
||||
#include "../rx-includes.hpp"
|
||||
|
||||
/*! \file rx-timer.hpp
|
||||
|
||||
\brief Returns an observable that emits an integer at the specified time point.
|
||||
|
||||
\tparam Coordination the type of the scheduler (optional)
|
||||
|
||||
\param when time point when the value is emitted
|
||||
\param cn the scheduler to use for scheduling the items (optional)
|
||||
|
||||
\return Observable that emits an integer at the specified time point
|
||||
|
||||
\sample
|
||||
\snippet timer.cpp timepoint timer sample
|
||||
\snippet output.txt timepoint timer sample
|
||||
|
||||
\sample
|
||||
\snippet timer.cpp duration timer sample
|
||||
\snippet output.txt duration timer sample
|
||||
|
||||
\sample
|
||||
\snippet timer.cpp threaded timepoint timer sample
|
||||
\snippet output.txt threaded timepoint timer sample
|
||||
|
||||
\sample
|
||||
\snippet timer.cpp threaded duration timer sample
|
||||
\snippet output.txt threaded duration timer sample
|
||||
*/
|
||||
|
||||
namespace rxcpp {
|
||||
|
||||
namespace sources {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class Coordination>
|
||||
struct timer : public source_base<long>
|
||||
{
|
||||
typedef timer<Coordination> this_type;
|
||||
|
||||
typedef rxu::decay_t<Coordination> coordination_type;
|
||||
typedef typename coordination_type::coordinator_type coordinator_type;
|
||||
|
||||
struct timer_initial_type
|
||||
{
|
||||
timer_initial_type(rxsc::scheduler::clock_type::time_point t, coordination_type cn)
|
||||
: when(t)
|
||||
, coordination(std::move(cn))
|
||||
{
|
||||
}
|
||||
rxsc::scheduler::clock_type::time_point when;
|
||||
coordination_type coordination;
|
||||
};
|
||||
timer_initial_type initial;
|
||||
|
||||
timer(rxsc::scheduler::clock_type::time_point t, coordination_type cn)
|
||||
: initial(t, std::move(cn))
|
||||
{
|
||||
}
|
||||
timer(rxsc::scheduler::clock_type::duration p, coordination_type cn)
|
||||
: initial(rxsc::scheduler::clock_type::time_point(), std::move(cn))
|
||||
{
|
||||
initial.when = initial.coordination.now() + p;
|
||||
}
|
||||
template<class Subscriber>
|
||||
void on_subscribe(Subscriber o) const {
|
||||
static_assert(is_subscriber<Subscriber>::value, "subscribe must be passed a subscriber");
|
||||
|
||||
// creates a worker whose lifetime is the same as this subscription
|
||||
auto coordinator = initial.coordination.create_coordinator(o.get_subscription());
|
||||
auto controller = coordinator.get_worker();
|
||||
|
||||
auto producer = [o](const rxsc::schedulable&) {
|
||||
// send the value and complete
|
||||
o.on_next(1L);
|
||||
o.on_completed();
|
||||
};
|
||||
|
||||
auto selectedProducer = on_exception(
|
||||
[&](){return coordinator.act(producer);},
|
||||
o);
|
||||
if (selectedProducer.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.schedule(initial.when, selectedProducer.get());
|
||||
}
|
||||
};
|
||||
|
||||
template<class TimePointOrDuration, class Coordination>
|
||||
struct defer_timer : public defer_observable<
|
||||
rxu::all_true<
|
||||
std::is_convertible<TimePointOrDuration, rxsc::scheduler::clock_type::time_point>::value ||
|
||||
std::is_convertible<TimePointOrDuration, rxsc::scheduler::clock_type::duration>::value,
|
||||
is_coordination<Coordination>::value>,
|
||||
void,
|
||||
timer, Coordination>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*! @copydoc rx-timer.hpp
|
||||
*/
|
||||
template<class TimePointOrDuration>
|
||||
auto timer(TimePointOrDuration when)
|
||||
-> typename std::enable_if<
|
||||
detail::defer_timer<TimePointOrDuration, identity_one_worker>::value,
|
||||
typename detail::defer_timer<TimePointOrDuration, identity_one_worker>::observable_type>::type {
|
||||
return detail::defer_timer<TimePointOrDuration, identity_one_worker>::make(when, identity_current_thread());
|
||||
}
|
||||
|
||||
/*! @copydoc rx-timer.hpp
|
||||
*/
|
||||
template<class TimePointOrDuration, class Coordination>
|
||||
auto timer(TimePointOrDuration when, Coordination cn)
|
||||
-> typename std::enable_if<
|
||||
detail::defer_timer<TimePointOrDuration, Coordination>::value,
|
||||
typename detail::defer_timer<TimePointOrDuration, Coordination>::observable_type>::type {
|
||||
return detail::defer_timer<TimePointOrDuration, Coordination>::make(when, std::move(cn));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user