feat add rxcpp

This commit is contained in:
tqcq
2024-03-14 20:50:17 +08:00
parent 15bdc54bef
commit 90da26f0a4
124 changed files with 27992 additions and 511 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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