The package rpms/RxCpp.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/RxCpp.git/commit/?id=53a3580717e7....
Change:
+%ifnarch %{power64}
Thanks.
Full change:
============
commit 53a3580717e7927c0455fb4d5885d20a5b3bd562
Author: Björn Esser <besser82(a)fedoraproject.org>
Date: Fri May 18 19:41:39 2018 +0200
Initial import (rhbz#1579523)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d594513
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/RxCpp-4.0.0.tar.gz
diff --git a/RxCpp-4.0.0-to_master.patch b/RxCpp-4.0.0-to_master.patch
new file mode 100644
index 0000000..61fc73a
--- /dev/null
+++ b/RxCpp-4.0.0-to_master.patch
@@ -0,0 +1,2908 @@
+From b0e30f09e66f682d87e675e11f3a03db49c237b3 Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Wed, 22 Mar 2017 19:45:30 -0700
+Subject: [PATCH 01/29] Update README.md
+
+---
+ README.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/README.md b/README.md
+index 39b67ef09..e8b782486 100644
+--- a/README.md
++++ b/README.md
+@@ -7,7 +7,7 @@ Linux & OSX | [![Linux & Osx
Status](http://img.shields.io/travis/Reactive-Exten
+
+ Source | Badges |
+ ------------- | :--------------- |
+-Github | [![GitHub
license](https://img.shields.io/github/license/Reactive-Extensions/RxCpp....
<br/> [![GitHub
release](https://img.shields.io/github/release/Reactive-Extensions/RxCpp....
<br/> [![GitHub
commits](https://img.shields.io/github/commits-since/Reactive-Extensions/...
++Github | [![GitHub
license](https://img.shields.io/github/license/Reactive-Extensions/RxCpp....
<br/> [![GitHub
release](https://img.shields.io/github/release/Reactive-Extensions/RxCpp....
<br/> [![GitHub
commits](https://img.shields.io/github/commits-since/Reactive-Extensions/...
+ Gitter.im | [![Join in on
gitter.im](https://img.shields.io/gitter/room/Reactive-Extensions/RxCpp.svg?style=flat-square)](https://gitter.im/Reactive-Extensions/RxCpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+ Packages | [![NuGet
version](http://img.shields.io/nuget/v/RxCpp.svg?style=flat-square)](http...
[![vcpkg
port](https://img.shields.io/badge/vcpkg-port-blue.svg?style=flat-square)...
+ Documentation | [![rxcpp doxygen
documentation](https://img.shields.io/badge/rxcpp-latest-brightgreen.svg?style=flat-square)](http://reactive-extensions.github.io/RxCpp)
<br/> [![reactivex
intro](https://img.shields.io/badge/reactivex.io-intro-brightgreen.svg?style=flat-square)](http://reactivex.io/intro.html)
[![rx marble
diagrams](https://img.shields.io/badge/rxmarbles-diagrams-brightgreen.svg...
+
+From 00fdd5b890664222e1b8dca317907950eea1f8f6 Mon Sep 17 00:00:00 2001
+From: Grigoriy Chudnov <g.chudnov(a)gmail.com>
+Date: Thu, 30 Mar 2017 17:22:35 +0300
+Subject: [PATCH 02/29] appveyor vs2017 image update (#365)
+
+* appveyor vs2017 image update
+
+* update appveyor config
+---
+ appveyor.yml | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/appveyor.yml b/appveyor.yml
+index 97e26a369..68ea4349b 100644
+--- a/appveyor.yml
++++ b/appveyor.yml
+@@ -6,13 +6,16 @@ branches:
+ - master
+ - appveyor
+
+-image: Visual Studio 2017 RC
++image: Visual Studio 2017
+
+ environment:
+ matrix:
+- - VSVER: Visual Studio 12 2013 Win64
+- - VSVER: Visual Studio 14 2015 Win64
+- - VSVER: Visual Studio 15 2017 Win64
++ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
++ VSVER: Visual Studio 12 2013 Win64
++ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
++ VSVER: Visual Studio 14 2015 Win64
++ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
++ VSVER: Visual Studio 15 2017 Win64
+
+ platform:
+ - x64
+
+From e024142dc3b23c229e6b375fdf7c5516df7c8437 Mon Sep 17 00:00:00 2001
+From: Anatoly Shirokov <anatoly.shirokov(a)gmail.com>
+Date: Thu, 30 Mar 2017 18:42:44 +0300
+Subject: [PATCH 03/29] fixed
+
https://github.com/Reactive-Extensions/RxCpp/issues/366
+
+---
+ Rx/v2/src/rxcpp/schedulers/rx-test.hpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/schedulers/rx-test.hpp
b/Rx/v2/src/rxcpp/schedulers/rx-test.hpp
+index 86d426aaa..3f73e526a 100644
+--- a/Rx/v2/src/rxcpp/schedulers/rx-test.hpp
++++ b/Rx/v2/src/rxcpp/schedulers/rx-test.hpp
+@@ -340,8 +340,9 @@ class hot_observable
+ template<class T>
+ rxt::testable_observable<T>
test_type::make_hot_observable(std::vector<rxn::recorded<std::shared_ptr<rxn::detail::notification_base<T>>>>
messages) const
+ {
+- return rxt::testable_observable<T>(
+- std::make_shared<hot_observable<T>>(state,
create_worker(composite_subscription()), std::move(messages)));
++ auto worker = create_worker(composite_subscription());
++ auto shared = std::make_shared<hot_observable<T>>(state, worker,
std::move(messages));
++ return rxt::testable_observable<T>(shared);
+ }
+
+ template<class F>
+
+From 201dd99b6494564c9e8990d0a5c32b23431128d4 Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Mon, 10 Apr 2017 16:03:58 -0700
+Subject: [PATCH 04/29] Kirkshoop/filterimprovement (#371)
+
+* filter: mutable predicate and value forwarding
+
+* add as_const to protect predicate from stealing
+---
+ Rx/v2/src/rxcpp/operators/rx-filter.hpp | 11 ++++++----
+ Rx/v2/src/rxcpp/rx-util.hpp | 38 +++++++++++++++++++++------------
+ 2 files changed, 31 insertions(+), 18 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/operators/rx-filter.hpp
b/Rx/v2/src/rxcpp/operators/rx-filter.hpp
+index ef6e133d9..86ce64920 100644
+--- a/Rx/v2/src/rxcpp/operators/rx-filter.hpp
++++ b/Rx/v2/src/rxcpp/operators/rx-filter.hpp
+@@ -58,22 +58,25 @@ struct filter
+ typedef rxu::decay_t<Subscriber> dest_type;
+ typedef observer<value_type, this_type> observer_type;
+ dest_type dest;
+- test_type test;
++ mutable test_type test;
+
+ filter_observer(dest_type d, test_type t)
+ : dest(std::move(d))
+ , test(std::move(t))
+ {
+ }
+- void on_next(source_value_type v) const {
++
++ template <class Value>
++ void on_next(Value&& v) const {
+ auto filtered = on_exception([&](){
+- return !this->test(v);},
++ return !this->test(rxu::as_const(v));
++ },
+ dest);
+ if (filtered.empty()) {
+ return;
+ }
+ if (!filtered.get()) {
+- dest.on_next(v);
++ dest.on_next(std::forward<Value>(v));
+ }
+ }
+ void on_error(std::exception_ptr e) const {
+diff --git a/Rx/v2/src/rxcpp/rx-util.hpp b/Rx/v2/src/rxcpp/rx-util.hpp
+index 77e0d3fcb..9c6534fc6 100644
+--- a/Rx/v2/src/rxcpp/rx-util.hpp
++++ b/Rx/v2/src/rxcpp/rx-util.hpp
+@@ -51,6 +51,16 @@ typename std::enable_if<!std::is_array<T0>::value &&
std::is_pod<T0>::value, std
+ return to_vector({t0, tn...});
+ }
+
++// lifted from
https://github.com/ericniebler/range-v3/blob/630fc70baa07cbfd222f329e44a3...
++// removed constexpr & noexcept to support older VC compilers
++template<typename T>
++/*constexpr*/ T const &as_const(T & t) /*noexcept*/
++{
++ return t;
++}
++template<typename T>
++void as_const(T const &&) = delete;
++
+ template<class T, T... ValueN>
+ struct values {};
+
+@@ -157,7 +167,7 @@ using types_checked_t = typename
types_checked_from<TN...>::type;
+ template<class Types, class =types_checked>
+ struct expand_value_types { struct type; };
+ template<class... TN>
+-struct expand_value_types<types<TN...>, types_checked_t<typename
std::decay<TN>::type::value_type...>>
++struct expand_value_types<types<TN...>, types_checked_t<typename
std::decay<TN>::type::value_type...>>
+ {
+ using type = types<typename std::decay<TN>::type::value_type...>;
+ };
+@@ -517,7 +527,7 @@ inline std::string what(std::exception_ptr ep) {
+ }
+ return std::string();
+ }
+-
++
+ namespace detail {
+
+ template <class T>
+@@ -754,7 +764,7 @@ struct is_string : std::false_type {
+ };
+
+ template <typename T>
+-struct is_string<T,
++struct is_string<T,
+ typename types_checked_from<
+ typename T::value_type,
+ typename T::traits_type,
+@@ -796,32 +806,32 @@ namespace rxu=util;
+
+
+ //
+-// due to an noisy static_assert issue in more than one std lib impl,
+-// rxcpp maintains a whitelist filter for the types that are allowed
++// due to an noisy static_assert issue in more than one std lib impl,
++// rxcpp maintains a whitelist filter for the types that are allowed
+ // to be hashed. this allows is_hashable<T> to work.
+ //
+ // NOTE: this should eventually be removed!
+ //
+-template <class T, typename = void>
++template <class T, typename = void>
+ struct filtered_hash;
+
+ #if RXCPP_HASH_ENUM
+-template <class T>
++template <class T>
+ struct filtered_hash<T, typename
std::enable_if<std::is_enum<T>::value>::type> : std::hash<T> {
+ };
+ #elif RXCPP_HASH_ENUM_UNDERLYING
+-template <class T>
++template <class T>
+ struct filtered_hash<T, typename
std::enable_if<std::is_enum<T>::value>::type> : std::hash<typename
std::underlying_type<T>::type> {
+ };
+ #endif
+
+-template <class T>
++template <class T>
+ struct filtered_hash<T, typename
std::enable_if<std::is_integral<T>::value>::type> : std::hash<T> {
+ };
+-template <class T>
++template <class T>
+ struct filtered_hash<T, typename
std::enable_if<std::is_pointer<T>::value>::type> : std::hash<T> {
+ };
+-template <class T>
++template <class T>
+ struct filtered_hash<T, typename
std::enable_if<rxu::is_string<T>::value>::type> : std::hash<T> {
+ };
+ template <class T>
+@@ -850,10 +860,10 @@ struct is_hashable
+ : std::false_type {};
+
+ template<typename T>
+-struct is_hashable<T,
++struct is_hashable<T,
+ typename rxu::types_checked_from<
+- typename filtered_hash<T>::result_type,
+- typename filtered_hash<T>::argument_type,
++ typename filtered_hash<T>::result_type,
++ typename filtered_hash<T>::argument_type,
+ typename std::result_of<filtered_hash<T>(T)>::type>::type>
+ : std::true_type {};
+
+
+From b41b15f1daf97519433742ff86adad9d0ae8acdd Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Mon, 10 Apr 2017 22:33:25 -0700
+Subject: [PATCH 05/29] fix async lifetime in window_toggle (#372)
+
+---
+ Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp | 4 +++-
+ Rx/v2/test/operators/window_toggle.cpp | 4 ++--
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp
b/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp
+index 1460feba3..c17d4bccd 100644
+--- a/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp
++++ b/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp
+@@ -120,6 +120,8 @@ struct window_toggle
+ localState->dest.remove(innerscope);
+ });
+
++ localState->dest.add(localState->cs);
++
+ auto source = on_exception(
+ [&](){return
localState->coordinator.in(localState->openings);},
+ localState->dest);
+@@ -252,7 +254,7 @@ struct window_toggle
+
+ static subscriber<T, observer_type> make(dest_type d, window_toggle_values
v) {
+ auto cs = composite_subscription();
+- auto coordinator = v.coordination.create_coordinator();
++ auto coordinator = v.coordination.create_coordinator(d.get_subscription());
+
+ return make_subscriber<T>(cs, observer_type(this_type(cs,
std::move(d), std::move(v), std::move(coordinator))));
+ }
+diff --git a/Rx/v2/test/operators/window_toggle.cpp
b/Rx/v2/test/operators/window_toggle.cpp
+index fc9088ba2..b85c1baac 100644
+--- a/Rx/v2/test/operators/window_toggle.cpp
++++ b/Rx/v2/test/operators/window_toggle.cpp
+@@ -35,7 +35,7 @@ SCENARIO("window toggle, basic",
"[window_toggle][operators]"){
+
+ WHEN("ints are split into windows"){
+ using namespace std::chrono;
+-
++
+ int wi = 0;
+
+ auto res = w.start(
+@@ -310,7 +310,7 @@ SCENARIO("window toggle, disposed",
"[window_toggle][operators]"){
+
+ THEN("there was one subscription and one unsubscription to the
observable"){
+ auto required = rxu::to_vector({
+- o_on.subscribe(200, 590)
++ o_on.subscribe(200, 420)
+ });
+ auto actual = xs.subscriptions();
+ REQUIRE(required == actual);
+
+From 18e8de22bbea8e295a80d9398599d50aa3e5be53 Mon Sep 17 00:00:00 2001
+From: Michael Maier <maiermic(a)users.noreply.github.com>
+Date: Thu, 27 Apr 2017 01:06:19 +0200
+Subject: [PATCH 06/29] subscribe in reverse order to observables (#375)
+
+---
+ Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp
b/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp
+index bce0596d4..febba994c 100644
+--- a/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp
++++ b/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp
+@@ -193,7 +193,7 @@ struct with_latest_from : public
operator_base<rxu::value_type_t<with_latest_fro
+ }
+ template<class State, int... IndexN>
+ void subscribe_all(std::shared_ptr<State> state, rxu::values<int,
IndexN...>) const {
+- bool subscribed[] = {(subscribe_one<IndexN>(state), true)...};
++ bool subscribed[] = {(subscribe_one<(sizeof...(IndexN)) - 1 -
IndexN>(state), true)...};
+ subscribed[0] = (*subscribed); // silence warning
+ }
+
+
+From 2caf64951c1505bf7511c72d8c245d929a2aecbc Mon Sep 17 00:00:00 2001
+From: Paul Esson <paul.esson(a)gmail.com>
+Date: Thu, 25 May 2017 15:36:23 +1000
+Subject: [PATCH 07/29] Update DeveloperManual.md (#380)
+
+Fix headings so they work with the Github markdown parser
+---
+ DeveloperManual.md | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/DeveloperManual.md b/DeveloperManual.md
+index 2d10b75e8..3ce4c2874 100644
+--- a/DeveloperManual.md
++++ b/DeveloperManual.md
+@@ -1,6 +1,6 @@
+-#Developer Manual
++# Developer Manual
+
+-##Some comments on the scheduler system
++## Some comments on the scheduler system
+
+ The scheduler in rxcpp v2 is based on the scheduler and worker constructs that *RxJava*
uses (Eric Meijer was involved) The docs for *RxJava* will have an explanation for
```scheduler``` and ```worker```. RxCpp adds ```schedulable```, ```coordination``` and
```coordinator```.
+
+
+From a1730f951348b602d5dee0643daafad6a913f7c7 Mon Sep 17 00:00:00 2001
+From: ZINEKS <wutiantong(a)icloud.com>
+Date: Mon, 5 Jun 2017 22:33:57 +0800
+Subject: [PATCH 08/29] Add get_subscription() for subject (#381)
+
+---
+ Rx/v2/src/rxcpp/subjects/rx-subject.hpp | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/Rx/v2/src/rxcpp/subjects/rx-subject.hpp
b/Rx/v2/src/rxcpp/subjects/rx-subject.hpp
+index 066f1527b..a77c0c4e8 100644
+--- a/Rx/v2/src/rxcpp/subjects/rx-subject.hpp
++++ b/Rx/v2/src/rxcpp/subjects/rx-subject.hpp
+@@ -254,6 +254,10 @@ class subject
+ return s.has_observers();
+ }
+
++ composite_subscription get_subscription() const {
++ return s.get_subscription();
++ }
++
+ subscriber_type get_subscriber() const {
+ return s.get_subscriber();
+ }
+
+From 1d75538fa780e530bcd724433257c65b3fe36b29 Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Thu, 15 Jun 2017 07:06:24 -0700
+Subject: [PATCH 09/29] disambiguate onerror from onnext (#383)
+
+---
+ Rx/v2/src/rxcpp/rx-observer.hpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Rx/v2/src/rxcpp/rx-observer.hpp b/Rx/v2/src/rxcpp/rx-observer.hpp
+index 39f427ed6..62aed3cfd 100644
+--- a/Rx/v2/src/rxcpp/rx-observer.hpp
++++ b/Rx/v2/src/rxcpp/rx-observer.hpp
+@@ -495,6 +495,7 @@ auto make_observer(OnNext on)
+ template<class T, class DefaultOnError = detail::OnErrorEmpty, class OnError>
+ auto make_observer(OnError oe)
+ -> typename std::enable_if<
++ !detail::is_on_next_of<T, OnError>::value &&
+ detail::is_on_error<OnError>::value,
+ observer<T, detail::stateless_observer_tag, detail::OnNextEmpty<T>,
OnError>>::type {
+ return observer<T, detail::stateless_observer_tag, detail::OnNextEmpty<T>,
OnError>(
+
+From 5aea424898994b3d409db268486202244cfe5053 Mon Sep 17 00:00:00 2001
+From: Grigoriy Chudnov <g.chudnov(a)gmail.com>
+Date: Sat, 15 Jul 2017 01:49:47 +0300
+Subject: [PATCH 10/29] fix timeout when no items are emitted (#387)
+
+---
+ Rx/v2/src/rxcpp/operators/rx-timeout.hpp | 14 ++++++++++++++
+ Rx/v2/test/operators/timeout.cpp | 18 +++++++++++-------
+ 2 files changed, 25 insertions(+), 7 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/operators/rx-timeout.hpp
b/Rx/v2/src/rxcpp/operators/rx-timeout.hpp
+index 6750e34e4..841df12f9 100644
+--- a/Rx/v2/src/rxcpp/operators/rx-timeout.hpp
++++ b/Rx/v2/src/rxcpp/operators/rx-timeout.hpp
+@@ -126,6 +126,20 @@ struct timeout
+ localState->cs.add([=](){
+ localState->worker.schedule(selectedDisposer.get());
+ });
++
++ auto work = [v, localState](const rxsc::schedulable&) {
++ auto new_id = ++localState->index;
++ auto produce_time = localState->worker.now() +
localState->period;
++
++ localState->worker.schedule(produce_time, produce_timeout(new_id,
localState));
++ };
++ auto selectedWork = on_exception(
++ [&](){return localState->coordinator.act(work);},
++ localState->dest);
++ if (selectedWork.empty()) {
++ return;
++ }
++ localState->worker.schedule(selectedWork.get());
+ }
+
+ static std::function<void(const rxsc::schedulable&)>
produce_timeout(std::size_t id, state_type state) {
+diff --git a/Rx/v2/test/operators/timeout.cpp b/Rx/v2/test/operators/timeout.cpp
+index 3005209d9..dbbea6c5d 100644
+--- a/Rx/v2/test/operators/timeout.cpp
++++ b/Rx/v2/test/operators/timeout.cpp
+@@ -3,13 +3,15 @@
+
+ using namespace std::chrono;
+
+-SCENARIO("should not timeout if the source never emits any items",
"[timeout][operators]"){
++SCENARIO("should timeout if the source never emits any items",
"[timeout][operators]"){
+ GIVEN("a source"){
+ auto sc = rxsc::make_test();
+ auto so = rx::synchronize_in_one_worker(sc);
+ auto w = sc.create_worker();
+ const rxsc::test::messages<int> on;
+
++ rxcpp::timeout_error ex("timeout has occurred");
++
+ auto xs = sc.make_hot_observable({
+ on.next(150, 1)
+ });
+@@ -23,15 +25,17 @@ SCENARIO("should not timeout if the source never emits any
items", "[timeout][op
+ }
+ );
+
+- THEN("the output is empty"){
+- auto required =
std::vector<rxsc::test::messages<int>::recorded_type>();
++ THEN("the error notification message is captured"){
++ auto required = rxu::to_vector({
++ on.error(211, ex)
++ });
+ auto actual = res.get_observer().messages();
+ REQUIRE(required == actual);
+ }
+
+ THEN("there was 1 subscription/unsubscription to the source"){
+ auto required = rxu::to_vector({
+- on.subscribe(200, 1001)
++ on.subscribe(200, 212)
+ });
+ auto actual = xs.subscriptions();
+ REQUIRE(required == actual);
+@@ -40,7 +44,7 @@ SCENARIO("should not timeout if the source never emits any
items", "[timeout][op
+ }
+ }
+
+-SCENARIO("should not timeout if the source observable is empty",
"[timeout][operators]"){
++SCENARIO("should not timeout if completed before the specified timeout
duration", "[timeout][operators]"){
+ GIVEN("a source"){
+ auto sc = rxsc::make_test();
+ auto so = rx::synchronize_in_one_worker(sc);
+@@ -56,7 +60,7 @@ SCENARIO("should not timeout if the source observable is
empty", "[timeout][oper
+
+ auto res = w.start(
+ [so, xs]() {
+- return xs.timeout(so, milliseconds(10));
++ return xs.timeout(so, milliseconds(100));
+ }
+ );
+
+@@ -189,7 +193,7 @@ SCENARIO("should not timeout if there is an error",
"[timeout][operators]"){
+
+ auto res = w.start(
+ [so, xs]() {
+- return xs.timeout(milliseconds(40), so);
++ return xs.timeout(milliseconds(100), so);
+ }
+ );
+
+
+From fea65be680234ba0677b84223de5563716b5c1aa Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Thu, 20 Jul 2017 16:28:54 -0700
+Subject: [PATCH 11/29] std::unexpected has been deprecated
+
+---
+ Rx/v2/src/rxcpp/rx-util.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Rx/v2/src/rxcpp/rx-util.hpp b/Rx/v2/src/rxcpp/rx-util.hpp
+index 9c6534fc6..97ff73f92 100644
+--- a/Rx/v2/src/rxcpp/rx-util.hpp
++++ b/Rx/v2/src/rxcpp/rx-util.hpp
+@@ -693,7 +693,7 @@ class unwinder
+ try {
+ (*function)();
+ } catch (...) {
+- std::unexpected();
++ std::terminate();
+ }
+ }
+ }
+
+From 139f190166912b01e0cf31efcc3518d0f5d8a3d6 Mon Sep 17 00:00:00 2001
+From: Daniel Rees <drees(a)developertown.com>
+Date: Sun, 23 Jul 2017 18:37:38 -0400
+Subject: [PATCH 12/29] Typo in rx-never documentation
+
+changed "rx-naver.hpp" to "rx-never.hpp"
+---
+ Rx/v2/src/rxcpp/sources/rx-never.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Rx/v2/src/rxcpp/sources/rx-never.hpp b/Rx/v2/src/rxcpp/sources/rx-never.hpp
+index cd6f4d03d..ea343996d 100644
+--- a/Rx/v2/src/rxcpp/sources/rx-never.hpp
++++ b/Rx/v2/src/rxcpp/sources/rx-never.hpp
+@@ -7,7 +7,7 @@
+
+ #include "../rx-includes.hpp"
+
+-/*! \file rx-naver.hpp
++/*! \file rx-never.hpp
+
+ \brief Returns an observable that never sends any items or notifications to
observer.
+
+
+From 5b7b2a5519f712a7831053865a4ae6082dac4ed5 Mon Sep 17 00:00:00 2001
+From: Peter Majchrak <petoknm(a)gmail.com>
+Date: Sat, 22 Jul 2017 19:37:05 +0200
+Subject: [PATCH 13/29] Add 'include' to the install path of the headers
+
+---
+ projects/CMake/CMakeLists.txt | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt
+index 6130d0591..7230ca782 100644
+--- a/projects/CMake/CMakeLists.txt
++++ b/projects/CMake/CMakeLists.txt
+@@ -133,5 +133,5 @@ SET_TARGET_PROPERTIES(RxCpp PROPERTIES LINKER_LANGUAGE CXX)
+
+ set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE CACHE BOOL "Don't require all
projects to be built in order to install" FORCE)
+
+-install(DIRECTORY ${RXCPP_DIR}/Rx/v2/src/rxcpp/ DESTINATION rxcpp
++install(DIRECTORY ${RXCPP_DIR}/Rx/v2/src/rxcpp/ DESTINATION include/rxcpp
+ FILES_MATCHING PATTERN "*.hpp")
+
+From 7d9859639c3abcf80d6a424dd3cffea8f11c7738 Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Fri, 1 Sep 2017 17:15:10 -0700
+Subject: [PATCH 14/29] shutdown event loop threads (#394)
+
+attempt to fix #393
+use event_loop lifetime to unsubscribe from new_thread workers
+
+tested with all the perf tests, but messing with thread lifetime can
+break existing code.
+---
+ Rx/v2/src/rxcpp/schedulers/rx-eventloop.hpp | 16 ++++++++++++----
+ Rx/v2/src/rxcpp/schedulers/rx-newthread.hpp | 18 ++++++++----------
+ 2 files changed, 20 insertions(+), 14 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/schedulers/rx-eventloop.hpp
b/Rx/v2/src/rxcpp/schedulers/rx-eventloop.hpp
+index da45e8d94..4f837670b 100644
+--- a/Rx/v2/src/rxcpp/schedulers/rx-eventloop.hpp
++++ b/Rx/v2/src/rxcpp/schedulers/rx-eventloop.hpp
+@@ -30,15 +30,21 @@ struct event_loop : public scheduler_interface
+
+ composite_subscription lifetime;
+ worker controller;
++ std::shared_ptr<const scheduler_interface> alive;
+
+ public:
+ virtual ~loop_worker()
+ {
+ }
+- loop_worker(composite_subscription cs, worker w)
++ loop_worker(composite_subscription cs, worker w, std::shared_ptr<const
scheduler_interface> alive)
+ : lifetime(cs)
+ , controller(w)
++ , alive(alive)
+ {
++ auto token = controller.add(cs);
++ cs.add([token, w](){
++ w.remove(token);
++ });
+ }
+
+ virtual clock_type::time_point now() const {
+@@ -57,6 +63,7 @@ struct event_loop : public scheduler_interface
+ mutable thread_factory factory;
+ scheduler newthread;
+ mutable std::atomic<std::size_t> count;
++ composite_subscription loops_lifetime;
+ std::vector<worker> loops;
+
+ public:
+@@ -69,7 +76,7 @@ struct event_loop : public scheduler_interface
+ {
+ auto remaining = std::max(std::thread::hardware_concurrency(), unsigned(4));
+ while (remaining--) {
+- loops.push_back(newthread.create_worker());
++ loops.push_back(newthread.create_worker(loops_lifetime));
+ }
+ }
+ explicit event_loop(thread_factory tf)
+@@ -79,11 +86,12 @@ struct event_loop : public scheduler_interface
+ {
+ auto remaining = std::max(std::thread::hardware_concurrency(), unsigned(4));
+ while (remaining--) {
+- loops.push_back(newthread.create_worker());
++ loops.push_back(newthread.create_worker(loops_lifetime));
+ }
+ }
+ virtual ~event_loop()
+ {
++ loops_lifetime.unsubscribe();
+ }
+
+ virtual clock_type::time_point now() const {
+@@ -91,7 +99,7 @@ struct event_loop : public scheduler_interface
+ }
+
+ virtual worker create_worker(composite_subscription cs) const {
+- return worker(cs, std::make_shared<loop_worker>(cs, loops[++count %
loops.size()]));
++ return worker(cs, std::make_shared<loop_worker>(cs, loops[++count %
loops.size()], this->shared_from_this()));
+ }
+ };
+
+diff --git a/Rx/v2/src/rxcpp/schedulers/rx-newthread.hpp
b/Rx/v2/src/rxcpp/schedulers/rx-newthread.hpp
+index c68399634..e31ed5511 100644
+--- a/Rx/v2/src/rxcpp/schedulers/rx-newthread.hpp
++++ b/Rx/v2/src/rxcpp/schedulers/rx-newthread.hpp
+@@ -37,16 +37,6 @@ struct new_thread : public scheduler_interface
+
+ virtual ~new_worker_state()
+ {
+- std::unique_lock<std::mutex> guard(lock);
+- if (worker.joinable() && worker.get_id() !=
std::this_thread::get_id()) {
+- lifetime.unsubscribe();
+- guard.unlock();
+- worker.join();
+- }
+- else {
+- lifetime.unsubscribe();
+- worker.detach();
+- }
+ }
+
+ explicit new_worker_state(composite_subscription cs)
+@@ -84,6 +74,14 @@ struct new_thread : public scheduler_interface
+ auto expired = std::move(keepAlive->q);
+ if (!keepAlive->q.empty()) std::terminate();
+ keepAlive->wake.notify_one();
++
++ if (keepAlive->worker.joinable() &&
keepAlive->worker.get_id() != std::this_thread::get_id()) {
++ guard.unlock();
++ keepAlive->worker.join();
++ }
++ else {
++ keepAlive->worker.detach();
++ }
+ });
+
+ state->worker = tf([keepAlive](){
+
+From de1df9fb30aa2951752a6c8fa39cc8f78916cbe5 Mon Sep 17 00:00:00 2001
+From: Eric Niebler <eniebler(a)boost.org>
+Date: Mon, 11 Sep 2017 16:23:44 -0700
+Subject: [PATCH 15/29] Correct prefix for test executables (#398)
+
+---
+ README.md | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/README.md b/README.md
+index e8b782486..8106c4ae8 100644
+--- a/README.md
++++ b/README.md
+@@ -212,11 +212,11 @@ The build only produces test and example binaries.
+ # Running tests
+
+ * You can use the CMake test runner `ctest`
+-* You can run the test binaries directly `rxcppv2_test_*`
++* You can run the test binaries directly `rxcpp_test_*`
+ * Tests can be selected by name or tag
+ Example of by-tag
+
+-`rxcppv2_test_subscription [perf]`
++`rxcpp_test_subscription [perf]`
+
+ # Documentation
+
+
+From e9931b7813ca96f54575768cfdeb998c4f15ed10 Mon Sep 17 00:00:00 2001
+From: Eric Niebler <eniebler(a)boost.org>
+Date: Mon, 11 Sep 2017 10:43:31 -0700
+Subject: [PATCH 16/29] Fix clang-trunk -Wunused-lambda-capture warnings
+
+---
+ Rx/v2/test/operators/group_by.cpp | 6 +++---
+ Rx/v2/test/operators/pairwise.cpp | 2 +-
+ Rx/v2/test/subjects/subject.cpp | 24 ++++++++++++------------
+ 3 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/Rx/v2/test/operators/group_by.cpp b/Rx/v2/test/operators/group_by.cpp
+index 606d7dfaf..2c7c177f9 100644
+--- a/Rx/v2/test/operators/group_by.cpp
++++ b/Rx/v2/test/operators/group_by.cpp
+@@ -47,13 +47,13 @@ SCENARIO("range partitioned by group_by across hardware threads
to derive pi", "
+ [](work w) -> int {return w.index %
std::thread::hardware_concurrency();},
+ [](work w){return w;}).
+ map(
+- [=, &c](rxcpp::grouped_observable<int, work> onproc) {
++ [=](rxcpp::grouped_observable<int, work> onproc) {
+ auto key = onproc.get_key();
+ // share a producer thread across all the ranges in this group
of chunks
+ auto producerthread =
rxcpp::observe_on_one_worker(rxcpp::observe_on_new_thread().create_coordinator().get_scheduler());
+ return onproc.
+ map(
+- [=, &c](work w){
++ [=](work w){
+ std::stringstream message;
+ message << std::setw(3) << w.index
<< ": range - " << w.first << "-" << w.last;
+
+@@ -123,7 +123,7 @@ SCENARIO("range partitioned by dividing work across hardware
threads to derive p
+ return work{index, first, last};
+ }).
+ map(
+- [=, &c](work w){
++ [=](work w){
+ std::stringstream message;
+ message << std::setw(3) << w.index << ":
range - " << w.first << "-" << w.last;
+
+diff --git a/Rx/v2/test/operators/pairwise.cpp b/Rx/v2/test/operators/pairwise.cpp
+index 7ba0c42c7..c28ae32c4 100644
+--- a/Rx/v2/test/operators/pairwise.cpp
++++ b/Rx/v2/test/operators/pairwise.cpp
+@@ -21,7 +21,7 @@ SCENARIO("pairwise - enough items to create pairs",
"[pairwise][operators]") {
+ WHEN("taken pairwise") {
+
+ auto res = w.start(
+- [xs, &invoked]() {
++ [xs]() {
+ return xs
+ | rxo::pairwise()
+ // forget type to workaround lambda deduction bug on msvc 2013
+diff --git a/Rx/v2/test/subjects/subject.cpp b/Rx/v2/test/subjects/subject.cpp
+index 79eb31f82..b6c6d67a8 100644
+--- a/Rx/v2/test/subjects/subject.cpp
++++ b/Rx/v2/test/subjects/subject.cpp
+@@ -138,7 +138,7 @@ class async_subscriber
+ };
+ }
+ SCENARIO("for loop calls ready on_next(int)",
"[hide][for][asyncobserver][ready][perf]"){
+- const int& onnextcalls = static_onnextcalls;
++ static const int& onnextcalls = static_onnextcalls;
+ GIVEN("a for loop"){
+ WHEN("calling on_next 100 million times"){
+ using namespace std::chrono;
+@@ -152,7 +152,7 @@ SCENARIO("for loop calls ready on_next(int)",
"[hide][for][asyncobserver][ready]
+ asyncwithready::async_subscriber<int, decltype(onnext)> scbr(onnext);
+ asyncwithready::ready::onthen_type chunk;
+ int i = 0;
+- chunk = [&chunk, scbr, i, onnextcalls]() mutable {
++ chunk = [&chunk, scbr, i]() mutable {
+ for (; i < onnextcalls && scbr.is_subscribed(); i++) {
+ auto controller = scbr.on_next(i);
+ if (!controller.is_ready()) {
+@@ -225,13 +225,13 @@ SCENARIO("for loop calls observer",
"[hide][for][observer][perf]"){
+ using namespace std::chrono;
+ typedef steady_clock clock;
+
+- int& c = aliased;
++ static int& c = aliased;
+ int n = 1;
+
+ c = 0;
+ auto start = clock::now();
+ auto o = rx::make_observer<int>(
+- [&c](int){++c;},
++ [](int){++c;},
+ [](std::exception_ptr){abort();});
+ for (int i = 0; i < onnextcalls; i++) {
+ o.on_next(i);
+@@ -251,13 +251,13 @@ SCENARIO("for loop calls subscriber",
"[hide][for][subscriber][perf]"){
+ using namespace std::chrono;
+ typedef steady_clock clock;
+
+- int& c = aliased;
++ static int& c = aliased;
+ int n = 1;
+
+ c = 0;
+ auto start = clock::now();
+ auto o = rx::make_subscriber<int>(
+- [&c](int){++c;},
++ [](int){++c;},
+ [](std::exception_ptr){abort();});
+ for (int i = 0; i < onnextcalls && o.is_subscribed(); i++) {
+ o.on_next(i);
+@@ -277,14 +277,14 @@ SCENARIO("range calls subscriber",
"[hide][range][subscriber][perf]"){
+ using namespace std::chrono;
+ typedef steady_clock clock;
+
+- int& c = aliased;
++ static int& c = aliased;
+ int n = 1;
+
+ c = 0;
+ auto start = clock::now();
+
+ rxs::range<int>(1, onnextcalls).subscribe(
+- [&c](int){
++ [](int){
+ ++c;
+ },
+ [](std::exception_ptr){abort();});
+@@ -297,7 +297,7 @@ SCENARIO("range calls subscriber",
"[hide][range][subscriber][perf]"){
+ }
+
+ SCENARIO("for loop calls subject",
"[hide][for][subject][subjects][long][perf]"){
+- const int& onnextcalls = static_onnextcalls;
++ static const int& onnextcalls = static_onnextcalls;
+ GIVEN("a for loop and a subject"){
+ WHEN("multicasting a million ints"){
+ using namespace std::chrono;
+@@ -316,7 +316,7 @@ SCENARIO("for loop calls subject",
"[hide][for][subject][subjects][long][perf]")
+
+ auto o = sub.get_subscriber();
+
+- o.add(rx::make_subscription([c, n, onnextcalls](){
++ o.add(rx::make_subscription([c, n](){
+ auto expected = n * onnextcalls;
+ REQUIRE(*c == expected);
+ }));
+@@ -371,7 +371,7 @@ SCENARIO("for loop calls subject",
"[hide][for][subject][subjects][long][perf]")
+ }
+
+ SCENARIO("range calls subject",
"[hide][range][subject][subjects][long][perf]"){
+- const int& onnextcalls = static_onnextcalls;
++ static const int& onnextcalls = static_onnextcalls;
+ GIVEN("a range and a subject"){
+ WHEN("multicasting a million ints"){
+ using namespace std::chrono;
+@@ -389,7 +389,7 @@ SCENARIO("range calls subject",
"[hide][range][subject][subjects][long][perf]"){
+
+ auto o = sub.get_subscriber();
+
+- o.add(rx::make_subscription([c, n, onnextcalls](){
++ o.add(rx::make_subscription([c, n](){
+ auto expected = n * onnextcalls;
+ REQUIRE(*c == expected);
+ }));
+
+From f6f7f502cc636c53bb4bf4ae0352b2a6a6c66e6b Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)microsoft.com>
+Date: Wed, 13 Sep 2017 07:17:15 -0700
+Subject: [PATCH 17/29] remove unused local
+
+---
+ Rx/v2/test/operators/pairwise.cpp | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/Rx/v2/test/operators/pairwise.cpp b/Rx/v2/test/operators/pairwise.cpp
+index c28ae32c4..20f86dd1f 100644
+--- a/Rx/v2/test/operators/pairwise.cpp
++++ b/Rx/v2/test/operators/pairwise.cpp
+@@ -7,7 +7,6 @@ SCENARIO("pairwise - enough items to create pairs",
"[pairwise][operators]") {
+ auto w = sc.create_worker();
+ const rxsc::test::messages<int> on;
+ const rxsc::test::messages<std::tuple<int, int>> on_pairwise;
+- long invoked = 0;
+
+ auto xs = sc.make_cold_observable({
+ on.next(180, 1),
+
+From b50f4d63365fb95e0662900116bf56654f4a1a0d Mon Sep 17 00:00:00 2001
+From: Andrei Lebedev <lebdron(a)gmail.com>
+Date: Fri, 15 Sep 2017 20:45:33 +0800
+Subject: [PATCH 18/29] Fix rxcpp::observable<>::from<T>() when T is
+ non-default constructable
+
+---
+ Rx/v2/src/rxcpp/sources/rx-iterate.hpp | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/sources/rx-iterate.hpp
b/Rx/v2/src/rxcpp/sources/rx-iterate.hpp
+index cb526b3cc..07f50bf6c 100644
+--- a/Rx/v2/src/rxcpp/sources/rx-iterate.hpp
++++ b/Rx/v2/src/rxcpp/sources/rx-iterate.hpp
+@@ -183,8 +183,8 @@ auto iterate(Collection c, Coordination cn)
+ */
+ template<class T>
+ auto from()
+- -> decltype(iterate(std::array<T, 0>(), identity_immediate())) {
+- return iterate(std::array<T, 0>(), identity_immediate());
++ -> 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.
+
+@@ -198,8 +198,8 @@ auto from()
+ template<class T, class Coordination>
+ auto from(Coordination cn)
+ -> typename std::enable_if<is_coordination<Coordination>::value,
+- decltype( iterate(std::array<T, 0>(), std::move(cn)))>::type {
+- return iterate(std::array<T, 0>(), std::move(cn));
++ 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.
+
+
+From 1b2e0589f19cb34d8cd58803677701dcf2161876 Mon Sep 17 00:00:00 2001
+From: Andrei Lebedev <lebdron(a)gmail.com>
+Date: Fri, 15 Sep 2017 20:55:24 +0800
+Subject: [PATCH 19/29] Fix rxcpp::observable<>::range<T>() when T is
unsigned
+ type
+
+---
+ Rx/v2/src/rxcpp/sources/rx-range.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Rx/v2/src/rxcpp/sources/rx-range.hpp b/Rx/v2/src/rxcpp/sources/rx-range.hpp
+index d55ffffb2..c56ee1f4e 100644
+--- a/Rx/v2/src/rxcpp/sources/rx-range.hpp
++++ b/Rx/v2/src/rxcpp/sources/rx-range.hpp
+@@ -86,7 +86,7 @@ struct range : public source_base<T>
+ return;
+ }
+
+- if (std::abs(state.last - state.next) < std::abs(state.step)) {
++ 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);
+ }
+
+From 815e92158e3e0647b96d1331de1ecc5badcde3f8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Martin=20Kodovsk=C3=BD?= <martin.kodovsky(a)gmail.com>
+Date: Sat, 9 Dec 2017 22:39:51 +0100
+Subject: [PATCH 20/29] Add rx-merge-delay-error operator (#417)
+
+* Add rx-merge-delay-error operator
+
+* fix of msvc2013 compilation
+
+* fix #417 comments
+
+Added RXCPP_NOEXCEPT macro; Added doxygen scenarios for composite_exception and
merge_delay_error; Fixed composing exception in merge_delay_error operator; Modified test
for merge_delay_operator
+
+* #417 fix composite_exception example
+
+* #417 fix merge_delay_error doxygen example
+
+* fix: samples add among others in project doxygen CMakeLists.txt
+
+* fix: composite_exception.cpp example
+---
+ Rx/v2/examples/doxygen/composite_exception.cpp | 31 +++
+ Rx/v2/examples/doxygen/merge_delay_error.cpp | 97 +++++++
+ Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp | 304 ++++++++++++++++++++
+ Rx/v2/src/rxcpp/rx-composite_exception.hpp | 34 +++
+ Rx/v2/src/rxcpp/rx-includes.hpp | 7 +
+ Rx/v2/src/rxcpp/rx-observable.hpp | 11 +
+ Rx/v2/src/rxcpp/rx-operators.hpp | 6 +
+ Rx/v2/test/CMakeLists.txt | 1 +
+ Rx/v2/test/operators/merge_delay_error.cpp | 306 +++++++++++++++++++++
+ projects/doxygen/CMakeLists.txt | 2 +
+ 10 files changed, 799 insertions(+)
+ create mode 100644 Rx/v2/examples/doxygen/composite_exception.cpp
+ create mode 100644 Rx/v2/examples/doxygen/merge_delay_error.cpp
+ create mode 100644 Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp
+ create mode 100644 Rx/v2/src/rxcpp/rx-composite_exception.hpp
+ create mode 100644 Rx/v2/test/operators/merge_delay_error.cpp
+
+diff --git a/Rx/v2/examples/doxygen/composite_exception.cpp
b/Rx/v2/examples/doxygen/composite_exception.cpp
+new file mode 100644
+index 000000000..697b83f65
+--- /dev/null
++++ b/Rx/v2/examples/doxygen/composite_exception.cpp
+@@ -0,0 +1,31 @@
++#include "rxcpp/rx.hpp"
++namespace rxu=rxcpp::util;
++
++#include "rxcpp/rx-test.hpp"
++#include "catch.hpp"
++
++SCENARIO("composite_exception sample"){
++ printf("//! [composite_exception sample]\n");
++ auto o1 = rxcpp::observable<>::error<int>(std::runtime_error("Error
from source o1\n"));
++ auto o2 = rxcpp::observable<>::error<int>(std::runtime_error("Error
from source o2\n"));
++ auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(5)).map([](int)
{return 3;});
++ auto values = o1.merge_delay_error(o2, o3);
++ values.
++ subscribe(
++ [](int v){printf("OnNext: %d\n", v);},
++ [](std::exception_ptr composite_e) {
++ printf("OnError %s\n", rxu::what(composite_e).c_str());
++ try { std::rethrow_exception(composite_e); }
++ catch(rxcpp::composite_exception ce) {
++ for(std::exception_ptr particular_e : ce.exceptions) {
++
++ try{ std::rethrow_exception(particular_e); }
++ catch(std::runtime_error error) { printf(" *** %s\n",
error.what()); }
++
++ }
++ }
++ },
++ [](){printf("OnCompleted\n");}
++ );
++ printf("//! [composite_exception sample]\n");
++}
+diff --git a/Rx/v2/examples/doxygen/merge_delay_error.cpp
b/Rx/v2/examples/doxygen/merge_delay_error.cpp
+new file mode 100644
+index 000000000..8c28cd882
+--- /dev/null
++++ b/Rx/v2/examples/doxygen/merge_delay_error.cpp
+@@ -0,0 +1,97 @@
++#include "rxcpp/rx.hpp"
++namespace rxu=rxcpp::util;
++
++#include "rxcpp/rx-test.hpp"
++#include "catch.hpp"
++
++SCENARIO("merge_delay_error sample"){
++ printf("//! [merge_delay_error sample]\n");
++ auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(15)).map([](int)
{return 1;});
++ auto o2 = rxcpp::observable<>::error<int>(std::runtime_error("Error
from source\n"));
++ auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(5)).map([](int)
{return 3;});
++ auto values = o1.merge_delay_error(o2, o3);
++ values.
++ subscribe(
++ [](int v){printf("OnNext: %d\n", v);},
++ [](std::exception_ptr eptr) { printf("OnError %s\n",
rxu::what(eptr).c_str()); },
++ [](){printf("OnCompleted\n");});
++ printf("//! [merge_delay_error sample]\n");
++}
++
++SCENARIO("implicit merge_delay_error sample"){
++ printf("//! [implicit merge_delay_error sample]\n");
++ auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(15)).map([](int)
{return 1;});
++ auto o2 = rxcpp::observable<>::error<int>(std::runtime_error("Error
from source\n"));
++ auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(5)).map([](int)
{return 3;});
++ auto base = rxcpp::observable<>::from(o1.as_dynamic(), o2, o3);
++ auto values = base.merge();
++ values.
++ subscribe(
++ [](int v){printf("OnNext: %d\n", v);},
++ [](std::exception_ptr eptr) { printf("OnError %s\n",
rxu::what(eptr).c_str()); },
++ [](){printf("OnCompleted\n");});
++ printf("//! [implicit merge_delay_error sample]\n");
++}
++
++std::string get_pid();
++
++SCENARIO("threaded merge_delay_error sample"){
++ printf("//! [threaded merge_delay_error sample]\n");
++ printf("[thread %s] Start task\n", get_pid().c_str());
++ auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(10)).map([](int)
{
++ printf("[thread %s] Timer1 fired\n", get_pid().c_str());
++ return 1;
++ });
++ auto o2 =
rxcpp::observable<>::timer(std::chrono::milliseconds(20)).flat_map([](int) {
++ std::stringstream ss;
++ ss << "[thread " << get_pid().c_str() << "] Timer2
failed\n";
++ printf("%s\n", ss.str().c_str());
++ ss.str(std::string());
++ ss << "(Error from thread: " << get_pid().c_str() <<
")\n";
++ return rxcpp::observable<>::error<int>(std::runtime_error(ss.str()));
++ });
++ auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(30)).map([](int)
{
++ printf("[thread %s] Timer3 fired\n", get_pid().c_str());
++ return 3;
++ });
++ auto values = o1.merge(rxcpp::observe_on_new_thread(), o2, o3);
++ values.
++ as_blocking().
++ subscribe(
++ [](int v){printf("[thread %s] OnNext: %d\n", get_pid().c_str(), v);},
++ [](std::exception_ptr eptr) { printf("[thread %s] OnError %s\n",
get_pid().c_str(), rxu::what(eptr).c_str()); },
++ [](){printf("[thread %s] OnCompleted\n", get_pid().c_str());});
++ printf("[thread %s] Finish task\n", get_pid().c_str());
++ printf("//! [threaded merge_delay_error sample]\n");
++}
++
++SCENARIO("threaded implicit merge_delay_error sample"){
++ printf("//! [threaded implicit merge_delay_error sample]\n");
++ printf("[thread %s] Start task\n", get_pid().c_str());
++ auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(10)).map([](int)
{
++ printf("[thread %s] Timer1 fired\n", get_pid().c_str());
++ return 1;
++ });
++ auto o2 =
rxcpp::observable<>::timer(std::chrono::milliseconds(20)).flat_map([](int) {
++ std::stringstream ss;
++ ss << "[thread " << get_pid().c_str() << "] Timer2
failed\n";
++ printf("%s\n", ss.str().c_str());
++ ss.str(std::string());
++ ss << "(Error from thread: " << get_pid().c_str() <<
")\n";
++ return rxcpp::observable<>::error<int>(std::runtime_error(ss.str()));
++ });
++ auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(30)).map([](int)
{
++ printf("[thread %s] Timer3 fired\n", get_pid().c_str());
++ return 3;
++ });
++ auto base = rxcpp::observable<>::from(o1.as_dynamic(), o2, o3);
++ auto values = base.merge(rxcpp::observe_on_new_thread());
++ values.
++ as_blocking().
++ subscribe(
++ [](int v){printf("[thread %s] OnNext: %d\n", get_pid().c_str(), v);},
++ [](std::exception_ptr eptr) { printf("[thread %s] OnError %s\n",
get_pid().c_str(), rxu::what(eptr).c_str()); },
++ [](){printf("[thread %s] OnCompleted\n", get_pid().c_str());});
++ printf("[thread %s] Finish task\n", get_pid().c_str());
++ printf("//! [threaded implicit merge_delay_error sample]\n");
++}
+diff --git a/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp
b/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp
+new file mode 100644
+index 000000000..43fdee326
+--- /dev/null
++++ b/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp
+@@ -0,0 +1,304 @@
++// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt
in the project root for license information.
++
++#pragma once
++
++/*! \file rx-merge_delay_error.hpp
++
++ \brief For each given observable subscribe.
++ For each item emitted from all of the given observables, deliver from
the new observable that is returned.
++ The first error to occure is hold off until all of the given
non-error-emitting observables have finished their emission.
++
++ There are 2 variants of the operator:
++ - The source observable emits nested observables, nested observables
are merged.
++ - The source observable and the arguments v0...vn are used to provide
the observables to merge.
++
++ \tparam Coordination the type of the scheduler (optional).
++ \tparam Value0 ... (optional).
++ \tparam ValueN types of source observables (optional).
++
++ \param cn the scheduler to synchronize sources from different contexts
(optional).
++ \param v0 ... (optional).
++ \param vn source observables (optional).
++
++ \return
Observable that emits items that are the result of
flattening the observables emitted by the source observable.
++
++ If scheduler is omitted, identity_current_thread is used.
++
++ \sample
++ \snippet merge_delay_error.cpp threaded implicit merge sample
++ \snippet output.txt threaded implicit merge sample
++
++ \sample
++ \snippet merge_delay_error.cpp implicit merge sample
++ \snippet output.txt implicit merge sample
++
++ \sample
++ \snippet merge_delay_error.cpp merge sample
++ \snippet output.txt merge sample
++
++ \sample
++ \snippet merge_delay_error.cpp threaded merge sample
++ \snippet output.txt threaded merge sample
++*/
++
++#if !defined(RXCPP_OPERATORS_RX_MERGE_DELAY_ERROR_HPP)
++#define RXCPP_OPERATORS_RX_MERGE_DELAY_ERROR_HPP
++
++#include "rx-merge.hpp"
++
++#include "../rx-composite_exception.hpp"
++
++namespace rxcpp {
++
++namespace operators {
++
++namespace detail {
++
++template<class T, class Observable, class Coordination>
++struct merge_delay_error
++ : public operator_base<rxu::value_type_t<rxu::decay_t<T>>>
++{
++ //static_assert(is_observable<Observable>::value, "merge requires an
observable");
++ //static_assert(is_observable<T>::value, "merge requires an
observable that contains observables");
++
++ typedef merge_delay_error<T, Observable, Coordination> this_type;
++
++ typedef rxu::decay_t<T> source_value_type;
++ typedef rxu::decay_t<Observable> source_type;
++
++ typedef typename source_type::source_operator_type source_operator_type;
++ typedef typename source_value_type::value_type value_type;
++
++ typedef rxu::decay_t<Coordination> coordination_type;
++ typedef typename coordination_type::coordinator_type coordinator_type;
++
++ struct values
++ {
++ values(source_operator_type o, coordination_type sf)
++ : source_operator(std::move(o))
++ , coordination(std::move(sf))
++ {
++ }
++ source_operator_type source_operator;
++ coordination_type coordination;
++ };
++ values initial;
++
++ merge_delay_error(const source_type& o, coordination_type sf)
++ : initial(o.source_operator, std::move(sf))
++ {
++ }
++
++ template<class Subscriber>
++ void on_subscribe(Subscriber scbr) const {
++ static_assert(is_subscriber<Subscriber>::value, "subscribe
must be passed a subscriber");
++
++ typedef Subscriber output_type;
++
++ struct merge_state_type
++ : public std::enable_shared_from_this<merge_state_type>
++ , public values
++ {
++ merge_state_type(values i, coordinator_type coor, output_type
oarg)
++ : values(i)
++ , source(i.source_operator)
++ , pendingCompletions(0)
++ , coordinator(std::move(coor))
++ , out(std::move(oarg))
++ {
++ }
++ observable<source_value_type, source_operator_type>
source;
++ // on_completed on the output must wait until all the
++ // subscriptions have received on_completed
++ int pendingCompletions;
++ composite_exception exception;;
++ coordinator_type coordinator;
++ output_type out;
++ };
++
++ auto coordinator =
initial.coordination.create_coordinator(scbr.get_subscription());
++
++ // take a copy of the values for each subscription
++ auto state = std::make_shared<merge_state_type>(initial,
std::move(coordinator), std::move(scbr));
++
++ composite_subscription outercs;
++
++ // when the out observer is unsubscribed all the
++ // inner subscriptions are unsubscribed as well
++ state->out.add(outercs);
++
++ auto source = on_exception(
++ [&](){return state->coordinator.in(state->source);},
++ state->out);
++ if (source.empty()) {
++ return;
++ }
++
++ ++state->pendingCompletions;
++ // this subscribe does not share the observer subscription
++ // so that when it is unsubscribed the observer can be called
++ // until the inner subscriptions have finished
++ auto sink = make_subscriber<source_value_type>(
++ state->out,
++ outercs,
++ // on_next
++ [state](source_value_type st) {
++
++ composite_subscription innercs;
++
++ // when the out observer is unsubscribed all the
++ // inner subscriptions are unsubscribed as well
++ auto innercstoken = state->out.add(innercs);
++
++ innercs.add(make_subscription([state, innercstoken](){
++ state->out.remove(innercstoken);
++ }));
++
++ auto selectedSource = state->coordinator.in(st);
++
++ ++state->pendingCompletions;
++ // this subscribe does not share the source
subscription
++ // so that when it is unsubscribed the source will
continue
++ auto sinkInner = make_subscriber<value_type>(
++ state->out,
++ innercs,
++ // on_next
++ [state, st](value_type ct) {
++ state->out.on_next(std::move(ct));
++ },
++ // on_error
++ [state](std::exception_ptr e) {
++ if(--state->pendingCompletions == 0)
{
++ state->out.on_error(
++
std::make_exception_ptr(std::move(state->exception.add(e))));
++ } else {
++ state->exception.add(e);
++ }
++ },
++ //on_completed
++ [state](){
++ if (--state->pendingCompletions == 0)
{
++ if(!state->exception.empty())
{
++ state->out.on_error(
++
std::make_exception_ptr(std::move(state->exception)));
++ } else {
++
state->out.on_completed();
++ }
++ }
++ }
++ );
++
++ auto selectedSinkInner =
state->coordinator.out(sinkInner);
++ selectedSource.subscribe(std::move(selectedSinkInner));
++ },
++ // on_error
++ [state](std::exception_ptr e) {
++ if(--state->pendingCompletions == 0) {
++ state->out.on_error(
++
std::make_exception_ptr(std::move(state->exception.add(e))));
++ } else {
++ state->exception.add(e);
++ }
++ },
++ // on_completed
++ [state]() {
++ if (--state->pendingCompletions == 0) {
++ if(!state->exception.empty()) {
++ state->out.on_error(
++
std::make_exception_ptr(std::move(state->exception)));
++ } else {
++ state->out.on_completed();
++ }
++ }
++ }
++ );
++ auto selectedSink = on_exception(
++ [&](){return state->coordinator.out(sink);},
++ state->out);
++ if (selectedSink.empty()) {
++ return;
++ }
++ source->subscribe(std::move(selectedSink.get()));
++ }
++};
++
++}
++
++/*! @copydoc rx-merge-delay-error.hpp
++*/
++template<class... AN>
++auto merge_delay_error(AN&&... an)
++ -> operator_factory<merge_delay_error_tag, AN...> {
++ return operator_factory<merge_delay_error_tag,
AN...>(std::make_tuple(std::forward<AN>(an)...));
++}
++
++}
++
++template<>
++struct member_overload<merge_delay_error_tag>
++{
++ template<class Observable,
++ class Enabled = rxu::enable_if_all_true_type_t<
++ is_observable<Observable>>,
++ class SourceValue = rxu::value_type_t<Observable>,
++ class Merge = rxo::detail::merge_delay_error<SourceValue,
rxu::decay_t<Observable>, identity_one_worker>,
++ class Value = rxu::value_type_t<SourceValue>,
++ class Result = observable<Value, Merge>
++ >
++ static Result member(Observable&& o) {
++ return Result(Merge(std::forward<Observable>(o),
identity_current_thread()));
++ }
++
++ template<class Observable, class Coordination,
++ class Enabled = rxu::enable_if_all_true_type_t<
++ is_observable<Observable>,
++ is_coordination<Coordination>>,
++ class SourceValue = rxu::value_type_t<Observable>,
++ class Merge = rxo::detail::merge_delay_error<SourceValue,
rxu::decay_t<Observable>, rxu::decay_t<Coordination>>,
++ class Value = rxu::value_type_t<SourceValue>,
++ class Result = observable<Value, Merge>
++ >
++ static Result member(Observable&& o, Coordination&& cn) {
++ return Result(Merge(std::forward<Observable>(o),
std::forward<Coordination>(cn)));
++ }
++
++ template<class Observable, class Value0, class... ValueN,
++ class Enabled = rxu::enable_if_all_true_type_t<
++ all_observables<Observable, Value0, ValueN...>>,
++ class EmittedValue = rxu::value_type_t<Observable>,
++ class SourceValue = observable<EmittedValue>,
++ class ObservableObservable = observable<SourceValue>,
++ class Merge = typename
rxu::defer_type<rxo::detail::merge_delay_error, SourceValue, ObservableObservable,
identity_one_worker>::type,
++ class Value = rxu::value_type_t<Merge>,
++ class Result = observable<Value, Merge>
++ >
++ static Result member(Observable&& o, Value0&& v0,
ValueN&&... vn) {
++ return Result(Merge(rxs::from(o.as_dynamic(), v0.as_dynamic(),
vn.as_dynamic()...), identity_current_thread()));
++ }
++
++ template<class Observable, class Coordination, class Value0, class...
ValueN,
++ class Enabled = rxu::enable_if_all_true_type_t<
++ all_observables<Observable, Value0, ValueN...>,
++ is_coordination<Coordination>>,
++ class EmittedValue = rxu::value_type_t<Observable>,
++ class SourceValue = observable<EmittedValue>,
++ class ObservableObservable = observable<SourceValue>,
++ class Merge = typename
rxu::defer_type<rxo::detail::merge_delay_error, SourceValue, ObservableObservable,
rxu::decay_t<Coordination>>::type,
++ class Value = rxu::value_type_t<Merge>,
++ class Result = observable<Value, Merge>
++ >
++ static Result member(Observable&& o, Coordination&& cn,
Value0&& v0, ValueN&&... vn) {
++ return Result(Merge(rxs::from(o.as_dynamic(), v0.as_dynamic(),
vn.as_dynamic()...), std::forward<Coordination>(cn)));
++ }
++
++ template<class... AN>
++ static operators::detail::merge_invalid_t<AN...> member(AN...) {
++ std::terminate();
++ return {};
++ static_assert(sizeof...(AN) == 10000, "merge_delay_error takes
(optional Coordination, optional Value0, optional ValueN...)");
++ }
++};
++
++}
++
++#endif
+diff --git a/Rx/v2/src/rxcpp/rx-composite_exception.hpp
b/Rx/v2/src/rxcpp/rx-composite_exception.hpp
+new file mode 100644
+index 000000000..333f291d6
+--- /dev/null
++++ b/Rx/v2/src/rxcpp/rx-composite_exception.hpp
+@@ -0,0 +1,34 @@
++// 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_COMPOSITE_EXCEPTION_HPP)
++#define RXCPP_SOURCES_RX_COMPOSITE_EXCEPTION_HPP
++
++#include "rx-includes.hpp"
++
++namespace rxcpp {
++
++struct composite_exception : std::exception {
++
++ typedef std::vector<std::exception_ptr> exception_values;
++
++ virtual const char *what() const RXCPP_NOEXCEPT override {
++ return "rxcpp composite exception";
++ }
++
++ virtual bool empty() const {
++ return exceptions.empty();
++ }
++
++ virtual composite_exception add(std::exception_ptr exception_ptr) {
++ exceptions.push_back(exception_ptr);
++ return *this;
++ }
++
++ exception_values exceptions;
++};
++
++}
++
++#endif
+diff --git a/Rx/v2/src/rxcpp/rx-includes.hpp b/Rx/v2/src/rxcpp/rx-includes.hpp
+index 3527f01ee..aefa1902c 100644
+--- a/Rx/v2/src/rxcpp/rx-includes.hpp
++++ b/Rx/v2/src/rxcpp/rx-includes.hpp
+@@ -125,6 +125,12 @@
+ #define _VARIADIC_MAX 10
+ #endif
+
++#if defined(_MSC_VER) && (_MSC_VER <= 1800)
++#define RXCPP_NOEXCEPT
++#else
++#define RXCPP_NOEXCEPT noexcept
++#endif
++
+ #pragma push_macro("min")
+ #pragma push_macro("max")
+ #undef min
+@@ -203,6 +209,7 @@
+ #include "operators/rx-ignore_elements.hpp"
+ #include "operators/rx-map.hpp"
+ #include "operators/rx-merge.hpp"
++#include "operators/rx-merge_delay_error.hpp"
+ #include "operators/rx-observe_on.hpp"
+ #include "operators/rx-on_error_resume_next.hpp"
+ #include "operators/rx-pairwise.hpp"
+diff --git a/Rx/v2/src/rxcpp/rx-observable.hpp b/Rx/v2/src/rxcpp/rx-observable.hpp
+index ef96d36d7..3a3124005 100644
+--- a/Rx/v2/src/rxcpp/rx-observable.hpp
++++ b/Rx/v2/src/rxcpp/rx-observable.hpp
+@@ -1023,6 +1023,17 @@ class observable
+ return observable_member(merge_tag{}, *this,
std::forward<AN>(an)...);
+ }
+
++ /*! @copydoc rx-merge_delay_error.hpp
++ */
++ template<class... AN>
++ auto merge_delay_error(AN... an) const
++ /// \cond SHOW_SERVICE_MEMBERS
++ -> decltype(observable_member(merge_delay_error_tag{}, *(this_type*)nullptr,
std::forward<AN>(an)...))
++ /// \endcond
++ {
++ return observable_member(merge_delay_error_tag{}, *this,
std::forward<AN>(an)...);
++ }
++
+ /*! @copydoc rx-amb.hpp
+ */
+ template<class... AN>
+diff --git a/Rx/v2/src/rxcpp/rx-operators.hpp b/Rx/v2/src/rxcpp/rx-operators.hpp
+index 0fa5d5884..15e8b54bb 100644
+--- a/Rx/v2/src/rxcpp/rx-operators.hpp
++++ b/Rx/v2/src/rxcpp/rx-operators.hpp
+@@ -258,6 +258,12 @@ struct merge_tag {
+ static_assert(Included::value, "missing include: please #include
<rxcpp/operators/rx-merge.hpp>");
+ };
+ };
++struct merge_delay_error_tag {
++ template<class Included>
++ struct include_header{
++ static_assert(Included::value, "missing include: please #include
<rxcpp/operators/rx-merge_delay_error.hpp>");
++ };
++};
+
+ struct multicast_tag {
+ template<class Included>
+diff --git a/Rx/v2/test/CMakeLists.txt b/Rx/v2/test/CMakeLists.txt
+index 322872cba..1064c0f82 100644
+--- a/Rx/v2/test/CMakeLists.txt
++++ b/Rx/v2/test/CMakeLists.txt
+@@ -54,6 +54,7 @@ set(TEST_SOURCES
+ ${TEST_DIR}/operators/lift.cpp
+ ${TEST_DIR}/operators/map.cpp
+ ${TEST_DIR}/operators/merge.cpp
++ ${TEST_DIR}/operators/merge_delay_error.cpp
+ ${TEST_DIR}/operators/observe_on.cpp
+ ${TEST_DIR}/operators/on_error_resume_next.cpp
+ ${TEST_DIR}/operators/pairwise.cpp
+diff --git a/Rx/v2/test/operators/merge_delay_error.cpp
b/Rx/v2/test/operators/merge_delay_error.cpp
+new file mode 100644
+index 000000000..d560b453d
+--- /dev/null
++++ b/Rx/v2/test/operators/merge_delay_error.cpp
+@@ -0,0 +1,306 @@
++#include "../test.h"
++#include <rxcpp/operators/rx-reduce.hpp>
++#include <rxcpp/operators/rx-merge_delay_error.hpp>
++#include <rxcpp/operators/rx-observe_on.hpp>
++
++const int static_onnextcalls = 1000000;
++
++//merge_delay_error must work the very same way as `merge()` except the error handling
++
++SCENARIO("merge completes", "[merge][join][operators]"){
++ GIVEN("1 hot observable with 3 cold observables of ints."){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++ const rxsc::test::messages<rx::observable<int>> o_on;
++
++ auto ys1 = sc.make_cold_observable({
++ on.next(10, 101),
++ on.next(20, 102),
++ on.next(110, 103),
++ on.next(120, 104),
++ on.next(210, 105),
++ on.next(220, 106),
++ on.completed(230)
++ });
++
++ auto ys2 = sc.make_cold_observable({
++ on.next(10, 201),
++ on.next(20, 202),
++ on.next(30, 203),
++ on.next(40, 204),
++ on.completed(50)
++ });
++
++ auto ys3 = sc.make_cold_observable({
++ on.next(10, 301),
++ on.next(20, 302),
++ on.next(30, 303),
++ on.next(40, 304),
++ on.next(120, 305),
++ on.completed(150)
++ });
++
++ auto xs = sc.make_hot_observable({
++ o_on.next(300, ys1),
++ o_on.next(400, ys2),
++ o_on.next(500, ys3),
++ o_on.completed(600)
++ });
++
++ WHEN("each int is merged"){
++
++ auto res = w.start(
++ [&]() {
++ return xs
++ | rxo::merge_delay_error()
++ // forget type to workaround lambda deduction bug on msvc 2013
++ | rxo::as_dynamic();
++ }
++ );
++
++ THEN("the output contains merged ints"){
++ auto required = rxu::to_vector({
++ on.next(310, 101),
++ on.next(320, 102),
++ on.next(410, 103),
++ on.next(410, 201),
++ on.next(420, 104),
++ on.next(420, 202),
++ on.next(430, 203),
++ on.next(440, 204),
++ on.next(510, 105),
++ on.next(510, 301),
++ on.next(520, 106),
++ on.next(520, 302),
++ on.next(530, 303),
++ on.next(540, 304),
++ on.next(620, 305),
++ on.completed(650)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
xs"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 600)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys1"){
++ auto required = rxu::to_vector({
++ on.subscribe(300, 530)
++ });
++ auto actual = ys1.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys2"){
++ auto required = rxu::to_vector({
++ on.subscribe(400, 450)
++ });
++ auto actual = ys2.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys3"){
++ auto required = rxu::to_vector({
++ on.subscribe(500, 650)
++ });
++ auto actual = ys3.subscriptions();
++ REQUIRE(required == actual);
++ }
++ }
++ }
++}
++
++SCENARIO("variadic merge completes with error",
"[merge][join][operators]"){
++ GIVEN("1 hot observable with 3 cold observables of ints."){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++ const rxsc::test::messages<rx::observable<int>> o_on;
++
++ auto ys1 = sc.make_cold_observable({
++ on.next(10, 101),
++ on.next(20, 102),
++ on.next(110, 103),
++ on.next(120, 104),
++ on.next(210, 105),
++ on.next(230, 107),
++ on.completed(240)
++ });
++
++ auto ys2 = sc.make_cold_observable({
++ on.next(10, 201),
++ on.next(20, 202),
++ on.next(30, 203),
++ on.error(40, std::runtime_error("merge_delay_error on_error from
ys2")),
++ on.next(50, 205),
++ on.completed(60)
++ });
++
++ auto ys3 = sc.make_cold_observable({
++ on.next(10, 301),
++ on.next(20, 302),
++ on.next(30, 303),
++ on.next(40, 304),
++ on.next(120, 305),
++ on.completed(150)
++ });
++
++ WHEN("each int is merged"){
++
++ auto res = w.start(
++ [&]() {
++ return ys1
++ .merge_delay_error(ys2, ys3);
++ }
++ );
++
++ rx::composite_exception ex;
++ THEN("the output contains merged ints"){
++ auto required = rxu::to_vector({
++ on.next(210, 101),
++ on.next(210, 201),
++ on.next(210, 301),
++ on.next(220, 102),
++ on.next(220, 202),
++ on.next(220, 302),
++ on.next(230, 203),
++ on.next(230, 303),
++ on.next(240, 304),
++ on.next(310, 103),
++ on.next(320, 104),
++ on.next(320, 305),
++ on.next(410, 105),
++ on.next(430, 107),
++ on.error(440, ex)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys1"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 440)
++ });
++ auto actual = ys1.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys2"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 240)
++ });
++ auto actual = ys2.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys3"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 350)
++ });
++ auto actual = ys3.subscriptions();
++ REQUIRE(required == actual);
++ }
++ }
++ }
++}
++
++SCENARIO("variadic merge completes with 2 errors",
"[merge][join][operators]"){
++ GIVEN("1 hot observable with 3 cold observables of ints."){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++ const rxsc::test::messages<rx::observable<int>> o_on;
++
++ auto ys1 = sc.make_cold_observable({
++ on.next(10, 101),
++ on.next(20, 102),
++ on.next(110, 103),
++ on.next(120, 104),
++ on.next(210, 105),
++ on.error(220, std::runtime_error("merge_delay_error on_error from
ys1")),
++ on.next(230, 107),
++ on.completed(240)
++ });
++
++ auto ys2 = sc.make_cold_observable({
++ on.next(10, 201),
++ on.next(20, 202),
++ on.next(30, 203),
++ on.error(40, std::runtime_error("merge_delay_error on_error from
ys2")),
++ on.next(50, 205),
++ on.completed(60)
++ });
++
++ auto ys3 = sc.make_cold_observable({
++ on.next(10, 301),
++ on.next(20, 302),
++ on.next(30, 303),
++ on.next(40, 304),
++ on.next(120, 305),
++ on.completed(150)
++ });
++
++ WHEN("each int is merged"){
++
++ auto res = w.start(
++ [&]() {
++ return ys1
++ .merge_delay_error(ys2, ys3);
++ }
++ );
++
++ rx::composite_exception ex;
++ THEN("the output contains merged ints"){
++ auto required = rxu::to_vector({
++ on.next(210, 101),
++ on.next(210, 201),
++ on.next(210, 301),
++ on.next(220, 102),
++ on.next(220, 202),
++ on.next(220, 302),
++ on.next(230, 203),
++ on.next(230, 303),
++ on.next(240, 304),
++ on.next(310, 103),
++ on.next(320, 104),
++ on.next(320, 305),
++ on.next(410, 105),
++ on.error(420, ex)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys1"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 420)
++ });
++ auto actual = ys1.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys2"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 240)
++ });
++ auto actual = ys2.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was one subscription and one unsubscription to the
ys3"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 350)
++ });
++ auto actual = ys3.subscriptions();
++ REQUIRE(required == actual);
++ }
++ }
++ }
++}
+diff --git a/projects/doxygen/CMakeLists.txt b/projects/doxygen/CMakeLists.txt
+index f5e66c4b0..a3fcd364c 100644
+--- a/projects/doxygen/CMakeLists.txt
++++ b/projects/doxygen/CMakeLists.txt
+@@ -49,6 +49,7 @@ if(DOXYGEN_FOUND)
+ ${DOXY_EXAMPLES_SRC_DIR}/blocking_observable.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/buffer.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/combine_latest.cpp
++ ${DOXY_EXAMPLES_SRC_DIR}/composite_exception.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/concat.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/concat_map.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/contains.cpp
+@@ -75,6 +76,7 @@ if(DOXYGEN_FOUND)
+ ${DOXY_EXAMPLES_SRC_DIR}/map.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/math.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/merge.cpp
++ ${DOXY_EXAMPLES_SRC_DIR}/merge_delay_error.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/never.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/observe_on.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/on_error_resume_next.cpp
+
+From b84db4278e54e722fbbae794f573d1142261e9a3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Martin=20Kodovsk=C3=BD?= <martin.kodovsky(a)gmail.com>
+Date: Thu, 14 Dec 2017 06:02:38 +0100
+Subject: [PATCH 21/29] Add: Skip_while operator (#418)
+
+* #378 adding skip_while operator
+
+* #378 adding tests + fixing CMakeLists.txt
+
+* #378 test completion
+
+* #378 fix includes
+
+* #378 fix assignment in a condition
+
+* #378 fix assignment in a condition 2
+---
+ Rx/v2/examples/doxygen/skip_while.cpp | 17 ++
+ Rx/v2/src/rxcpp/operators/rx-skip_while.hpp | 131 +++++++++
+ Rx/v2/src/rxcpp/rx-includes.hpp | 1 +
+ Rx/v2/src/rxcpp/rx-observable.hpp | 11 +
+ Rx/v2/src/rxcpp/rx-operators.hpp | 7 +
+ Rx/v2/test/CMakeLists.txt | 1 +
+ Rx/v2/test/operators/skip_while.cpp | 434 ++++++++++++++++++++++++++++
+ projects/CMake/CMakeLists.txt | 2 +
+ projects/doxygen/CMakeLists.txt | 1 +
+ 9 files changed, 605 insertions(+)
+ create mode 100644 Rx/v2/examples/doxygen/skip_while.cpp
+ create mode 100644 Rx/v2/src/rxcpp/operators/rx-skip_while.hpp
+ create mode 100644 Rx/v2/test/operators/skip_while.cpp
+
+diff --git a/Rx/v2/examples/doxygen/skip_while.cpp
b/Rx/v2/examples/doxygen/skip_while.cpp
+new file mode 100644
+index 000000000..a98ce18b0
+--- /dev/null
++++ b/Rx/v2/examples/doxygen/skip_while.cpp
+@@ -0,0 +1,17 @@
++#include "rxcpp/rx.hpp"
++
++#include "rxcpp/rx-test.hpp"
++#include "catch.hpp"
++
++SCENARIO("skip_while sample"){
++ printf("//! [skip_while sample]\n");
++ auto values = rxcpp::observable<>::range(1, 8).
++ skip_while([](int v){
++ return v <= 4;
++ });
++ values.
++ subscribe(
++ [](int v){printf("OnNext: %d\n", v);},
++ [](){printf("OnCompleted\n");});
++ printf("//! [skip_while sample]\n");
++}
+diff --git a/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp
b/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp
+new file mode 100644
+index 000000000..fdd06b63e
+--- /dev/null
++++ b/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp
+@@ -0,0 +1,131 @@
++// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt
in the project root for license information.
++
++#pragma once
++
++/*! \file rx-skip_while.hpp
++
++ \brief Discards the first items fulfilling the predicate from this observable emit
them from the new observable that is returned.
++
++ \tparam Predicate the type of the predicate
++
++ \param t the predicate
++
++ \return An observable that discards the first items until condition emitted by the
source Observable is not fulfilling the predicate, or all of the items from the source
observable if the predicate never returns false
++
++ \sample
++ \snippet skip_while.cpp skip_while sample
++ \snippet output.txt skip_while sample
++*/
++
++#if !defined(RXCPP_OPERATORS_RX_SKIP_WHILE_HPP)
++#define RXCPP_OPERATORS_RX_SKIP_WHILE_HPP
++
++#include "../rx-includes.hpp"
++
++namespace rxcpp {
++
++namespace operators {
++
++namespace detail {
++
++template<class... AN>
++struct skip_while_invalid_arguments {};
++
++template<class... AN>
++struct skip_while_invalid : public
rxo::operator_base<skip_while_invalid_arguments<AN...>> {
++ using type = observable<skip_while_invalid_arguments<AN...>,
skip_while_invalid<AN...>>;
++};
++template<class... AN>
++using skip_while_invalid_t = typename skip_while_invalid<AN...>::type;
++
++template<class T, class Predicate>
++struct skip_while
++{
++ typedef rxu::decay_t<T> source_value_type;
++ typedef rxu::decay_t<Predicate> test_type;
++ test_type test;
++
++
++ skip_while(test_type t)
++ : test(std::move(t))
++ {
++ }
++
++ template<class Subscriber>
++ struct skip_while_observer
++ {
++ typedef skip_while_observer<Subscriber> this_type;
++ typedef source_value_type value_type;
++ typedef rxu::decay_t<Subscriber> dest_type;
++ typedef observer<value_type, this_type> observer_type;
++ dest_type dest;
++ test_type test;
++ bool pass;
++
++ skip_while_observer(dest_type d, test_type t)
++ : dest(std::move(d))
++ , test(std::move(t)),
++ pass(false)
++ {
++ }
++ void on_next(source_value_type v) {
++ if(pass || !test(v))
++ {
++ pass = true;
++ dest.on_next(v);
++ }
++ }
++ void on_error(std::exception_ptr e) const {
++ dest.on_error(e);
++ }
++ void on_completed() const {
++ dest.on_completed();
++ }
++
++ static subscriber<value_type, observer_type> make(dest_type d, test_type
t) {
++ return make_subscriber<value_type>(d, this_type(d, std::move(t)));
++ }
++ };
++
++ template<class Subscriber>
++ auto operator()(Subscriber dest) const
++ -> decltype(skip_while_observer<Subscriber>::make(std::move(dest), test))
{
++ return skip_while_observer<Subscriber>::make(std::move(dest), test);
++ }
++};
++
++}
++
++/*! @copydoc rx-skip_while.hpp
++*/
++template<class... AN>
++auto skip_while(AN&&... an)
++ -> operator_factory<skip_while_tag, AN...> {
++ return operator_factory<skip_while_tag,
AN...>(std::make_tuple(std::forward<AN>(an)...));
++ }
++
++}
++
++template<>
++struct member_overload<skip_while_tag>
++{
++ template<class Observable, class Predicate,
++ class SourceValue = rxu::value_type_t<Observable>,
++ class TakeWhile = rxo::detail::skip_while<SourceValue,
rxu::decay_t<Predicate>>>
++ static auto member(Observable&& o, Predicate&& p)
++ -> decltype(o.template
lift<SourceValue>(TakeWhile(std::forward<Predicate>(p)))) {
++ return o.template
lift<SourceValue>(TakeWhile(std::forward<Predicate>(p)));
++ }
++
++ template<class... AN>
++ static operators::detail::skip_while_invalid_t<AN...> member(const AN&...)
{
++ std::terminate();
++ return {};
++ static_assert(sizeof...(AN) == 10000, "skip_while takes
(Predicate)");
++ }
++};
++
++
++}
++
++#endif
+diff --git a/Rx/v2/src/rxcpp/rx-includes.hpp b/Rx/v2/src/rxcpp/rx-includes.hpp
+index aefa1902c..51045657e 100644
+--- a/Rx/v2/src/rxcpp/rx-includes.hpp
++++ b/Rx/v2/src/rxcpp/rx-includes.hpp
+@@ -221,6 +221,7 @@
+ #include "operators/rx-scan.hpp"
+ #include "operators/rx-sequence_equal.hpp"
+ #include "operators/rx-skip.hpp"
++#include "operators/rx-skip_while.hpp"
+ #include "operators/rx-skip_last.hpp"
+ #include "operators/rx-skip_until.hpp"
+ #include "operators/rx-start_with.hpp"
+diff --git a/Rx/v2/src/rxcpp/rx-observable.hpp b/Rx/v2/src/rxcpp/rx-observable.hpp
+index 3a3124005..496db0b5c 100644
+--- a/Rx/v2/src/rxcpp/rx-observable.hpp
++++ b/Rx/v2/src/rxcpp/rx-observable.hpp
+@@ -1361,6 +1361,17 @@ class observable
+ return observable_member(skip_tag{}, *this,
std::forward<AN>(an)...);
+ }
+
++ /*! @copydoc rx-skip.hpp
++ */
++ template<class... AN>
++ auto skip_while(AN... an) const
++ /// \cond SHOW_SERVICE_MEMBERS
++ -> decltype(observable_member(skip_while_tag{}, *(this_type*)nullptr,
std::forward<AN>(an)...))
++ /// \endcond
++ {
++ return observable_member(skip_while_tag{}, *this,
std::forward<AN>(an)...);
++ }
++
+ /*! @copydoc rx-skip_last.hpp
+ */
+ template<class... AN>
+diff --git a/Rx/v2/src/rxcpp/rx-operators.hpp b/Rx/v2/src/rxcpp/rx-operators.hpp
+index 15e8b54bb..9a5481aef 100644
+--- a/Rx/v2/src/rxcpp/rx-operators.hpp
++++ b/Rx/v2/src/rxcpp/rx-operators.hpp
+@@ -377,6 +377,13 @@ struct skip_tag {
+ };
+ };
+
++struct skip_while_tag {
++ template<class Included>
++ struct include_header{
++ static_assert(Included::value, "missing include: please #include
<rxcpp/operators/rx-skip_while.hpp>");
++ };
++};
++
+ struct skip_last_tag {
+ template<class Included>
+ struct include_header{
+diff --git a/Rx/v2/test/CMakeLists.txt b/Rx/v2/test/CMakeLists.txt
+index 1064c0f82..dcb998f81 100644
+--- a/Rx/v2/test/CMakeLists.txt
++++ b/Rx/v2/test/CMakeLists.txt
+@@ -67,6 +67,7 @@ set(TEST_SOURCES
+ ${TEST_DIR}/operators/scan.cpp
+ ${TEST_DIR}/operators/sequence_equal.cpp
+ ${TEST_DIR}/operators/skip.cpp
++ ${TEST_DIR}/operators/skip_while.cpp
+ ${TEST_DIR}/operators/skip_last.cpp
+ ${TEST_DIR}/operators/skip_until.cpp
+ ${TEST_DIR}/operators/start_with.cpp
+diff --git a/Rx/v2/test/operators/skip_while.cpp b/Rx/v2/test/operators/skip_while.cpp
+new file mode 100644
+index 000000000..cc773b12a
+--- /dev/null
++++ b/Rx/v2/test/operators/skip_while.cpp
+@@ -0,0 +1,434 @@
++#include "../test.h"
++#include <rxcpp/operators/rx-skip_while.hpp>
++
++namespace {
++ class not_equal_to {
++ int value;
++ public:
++ not_equal_to(int value) : value(value) { }
++ bool operator()(int i) const {
++ return i != value;
++ }
++ };
++}
++
++SCENARIO("skip_while not equal to 4", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ auto xs = sc.make_hot_observable({
++ on.next(150, 1),
++ on.next(210, 2),
++ on.next(220, 3),
++ on.next(230, 4),
++ on.next(240, 5),
++ on.completed(250)
++ });
++
++ WHEN("values before 4 are taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(4))
++ .as_dynamic();
++ }
++ );
++
++ THEN("the output only contains items sent while subscribed"){
++ auto required = rxu::to_vector({
++ on.next(230, 4),
++ on.next(240, 5),
++ on.completed(250)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 250)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
++
++SCENARIO("skip_while, complete after", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ auto xs = sc.make_hot_observable({
++ on.next(70, 6),
++ on.next(150, 4),
++ on.next(210, 9),
++ on.next(230, 13),
++ on.next(270, 7),
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ on.next(410, 15),
++ on.next(415, 16),
++ on.next(460, 72),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10),
++ on.completed(690)
++ });
++
++ WHEN("none are taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(0))
++ // forget type to workaround lambda deduction bug on msvc 2013
++ .as_dynamic();
++ }
++ );
++
++ THEN("the output contains no items sent while subscribed"){
++ auto required = rxu::to_vector({
++ on.completed(690)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 690)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
++
++SCENARIO("skip_while, complete before", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ auto xs = sc.make_hot_observable({
++ on.next(70, 6),
++ on.next(150, 4),
++ on.next(210, 9),
++ on.next(230, 13),
++ on.next(270, 7),
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ on.next(410, 15),
++ on.next(415, 16),
++ on.next(460, 72),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10),
++ on.completed(690)
++ });
++
++ WHEN("7 values are taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(72))
++ // forget type to workaround lambda deduction bug on msvc 2013
++ .as_dynamic();
++ }
++ );
++
++ THEN("the output only contains items sent while subscribed"){
++ auto required = rxu::to_vector({
++ on.next(460, 72),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10),
++ on.completed(690)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 690)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
++
++SCENARIO("skip_while, error after", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ std::runtime_error ex("skip_while on_error from source");
++
++ auto xs = sc.make_hot_observable({
++ on.next(70, 6),
++ on.next(150, 4),
++ on.next(210, 9),
++ on.next(230, 13),
++ on.next(270, 7),
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ on.next(410, 15),
++ on.next(415, 16),
++ on.next(460, 72),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10),
++ on.error(690, ex)
++ });
++
++ WHEN("no values are taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(0))
++ // forget type to workaround lambda deduction bug on msvc 2013
++ .as_dynamic();
++ }
++ );
++
++ THEN("the output only contains items sent while subscribed and the
error"){
++ auto required = rxu::to_vector({
++ on.error(690, ex)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 690)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
++
++SCENARIO("skip_while, error before", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ std::runtime_error ex("skip_while on_error from source");
++
++ auto xs = sc.make_hot_observable({
++ on.next(70, 6),
++ on.next(150, 4),
++ on.next(210, 9),
++ on.next(230, 13),
++ on.next(270, 7),
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ on.next(410, 15),
++ on.next(415, 16),
++ on.next(460, 72),
++ on.error(500, ex),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10)
++ });
++
++ WHEN("only one value is taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(72))
++ // forget type to workaround lambda deduction bug on msvc 2013
++ .as_dynamic();
++ }
++ );
++
++ THEN("the output only contains items sent while subscribed"){
++ auto required = rxu::to_vector({
++ on.next(460, 72),
++ on.error(500, ex)
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 500)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
++
++SCENARIO("skip_while, dispose before", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ auto xs = sc.make_hot_observable({
++ on.next(70, 6),
++ on.next(150, 100),
++ on.next(210, 9),
++ on.next(230, 13),
++ on.next(270, 7),
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ on.next(410, 15),
++ on.next(415, 16),
++ on.next(460, 72),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10)
++ });
++
++ WHEN("3 values are taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(100))
++ // forget type to workaround lambda deduction bug on msvc 2013
++ .as_dynamic();
++ },
++ 250
++ );
++
++ THEN("the output only contains items sent while subscribed"){
++ std::vector<rxcpp::notifications::recorded<std::shared_ptr<rxcpp::notifications::detail::notification_base<int>
> > > required;
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 250)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
++
++SCENARIO("skip_while, dispose after", "[skip_while][operators]"){
++ GIVEN("a source"){
++ auto sc = rxsc::make_test();
++ auto w = sc.create_worker();
++ const rxsc::test::messages<int> on;
++
++ auto xs = sc.make_hot_observable({
++ on.next(70, 6),
++ on.next(150, 4), //this is skipped due to delayed subscription
++ on.next(210, 9),
++ on.next(230, 13),
++ on.next(270, 7),
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ on.next(410, 15),
++ on.next(415, 16),
++ on.next(460, 72),
++ on.next(510, 76),
++ on.next(560, 32),
++ on.next(570, -100),
++ on.next(580, -3),
++ on.next(590, 5),
++ on.next(630, 10)
++ });
++
++ WHEN("5 values are taken"){
++
++ auto res = w.start(
++ [xs]() {
++ return xs
++ .skip_while(not_equal_to(1))
++ // forget type to workaround lambda deduction bug on msvc 2013
++ .as_dynamic();
++ },
++ 400
++ );
++
++ THEN("the output only contains items sent while subscribed"){
++ auto required = rxu::to_vector({
++ on.next(280, 1),
++ on.next(300, -1),
++ on.next(310, 3),
++ on.next(340, 8),
++ on.next(370, 11),
++ });
++ auto actual = res.get_observer().messages();
++ REQUIRE(required == actual);
++ }
++
++ THEN("there was 1 subscription/unsubscription to the source"){
++ auto required = rxu::to_vector({
++ on.subscribe(200, 400)
++ });
++ auto actual = xs.subscriptions();
++ REQUIRE(required == actual);
++ }
++
++ }
++ }
++}
+diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt
+index 7230ca782..542a91abb 100644
+--- a/projects/CMake/CMakeLists.txt
++++ b/projects/CMake/CMakeLists.txt
+@@ -49,6 +49,7 @@ set(RX_SOURCES
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-lift.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-map.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-merge.hpp
++ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-multicast.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-observe_on.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-on_error_resume_next.hpp
+@@ -63,6 +64,7 @@ set(RX_SOURCES
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-scan.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-skip.hpp
++ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-skip_last.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-skip_until.hpp
+ ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-start_with.hpp
+diff --git a/projects/doxygen/CMakeLists.txt b/projects/doxygen/CMakeLists.txt
+index a3fcd364c..6620a7afc 100644
+--- a/projects/doxygen/CMakeLists.txt
++++ b/projects/doxygen/CMakeLists.txt
+@@ -92,6 +92,7 @@ if(DOXYGEN_FOUND)
+ ${DOXY_EXAMPLES_SRC_DIR}/scope.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/sequence_equal.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/skip.cpp
++ ${DOXY_EXAMPLES_SRC_DIR}/skip_while.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/skip_last.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/skip_until.cpp
+ ${DOXY_EXAMPLES_SRC_DIR}/start_with.cpp
+
+From 76149330a666200b62422454a4fd8d3cd0a4ae37 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82(a)fedoraproject.org>
+Date: Thu, 3 May 2018 14:59:52 +0200
+Subject: [PATCH 22/29] Fix '-Wignored-qualifiers'
+
+---
+ Rx/v2/src/rxcpp/rx-subscription.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Rx/v2/src/rxcpp/rx-subscription.hpp b/Rx/v2/src/rxcpp/rx-subscription.hpp
+index 9c0046905..ee4e53ef1 100644
+--- a/Rx/v2/src/rxcpp/rx-subscription.hpp
++++ b/Rx/v2/src/rxcpp/rx-subscription.hpp
+@@ -379,7 +379,7 @@ class composite_subscription
+
+ composite_subscription()
+ : inner_type()
+- , subscription(*static_cast<const inner_type* const>(this))
++ , subscription(*static_cast<const inner_type*>(this))
+ {
+ }
+
+
+From 7cebbd4d2b3ac16249d538024e7f31eaa300c962 Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)gmail.com>
+Date: Fri, 4 May 2018 11:03:54 -0700
+Subject: [PATCH 23/29] Update README.md
+
+---
+ README.md | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/README.md b/README.md
+index 8106c4ae8..dbeaaabc0 100644
+--- a/README.md
++++ b/README.md
+@@ -12,8 +12,12 @@ Gitter.im | [![Join in on
gitter.im](https://img.shields.io/gitter/room/Reactive
+ Packages | [![NuGet
version](http://img.shields.io/nuget/v/RxCpp.svg?style=flat-square)](http...
[![vcpkg
port](https://img.shields.io/badge/vcpkg-port-blue.svg?style=flat-square)...
+ Documentation | [![rxcpp doxygen
documentation](https://img.shields.io/badge/rxcpp-latest-brightgreen.svg?style=flat-square)](http://reactive-extensions.github.io/RxCpp)
<br/> [![reactivex
intro](https://img.shields.io/badge/reactivex.io-intro-brightgreen.svg?style=flat-square)](http://reactivex.io/intro.html)
[![rx marble
diagrams](https://img.shields.io/badge/rxmarbles-diagrams-brightgreen.svg...
+
++# Usage
++
++__RxCpp__ is a header-only C++ library that only depends on the standard library. The
CMake build generates documentation and unit tests.
++
+ # Example
+-Add ```Rx/v2/src``` to the include paths
++Add `Rx/v2/src` to the include paths
+
+ [![lines from
bytes](https://img.shields.io/badge/blog%20post-lines%20from%20bytes-blue.svg?style=flat-square)](http://kirkshoop.github.io/async/rxcpp/c++/2015/07/07/rxcpp_-_parsing_bytes_to_lines_of_text.html)
+
+@@ -230,7 +234,5 @@ When Doxygen+Graphviz is installed, CMake creates a special build
task named `do
+
+ Before submitting a feature or substantial code contribution please discuss it with the
team and ensure it follows the product roadmap. Note that all code submissions will be
rigorously reviewed and tested by the Rx Team, and only those that meet an extremely high
bar for both quality and design/roadmap appropriateness will be merged into the source.
+
+-You will be prompted to submit a Contributor License Agreement form after submitting
your pull request. This needs to only be done once for any Microsoft OSS project. Fill in
the [Contributor License
Agreement](https://cla2.msopentech.com/) (CLA).
+-
+ # Microsoft Open Source Code of Conduct
+ This project has adopted the [Microsoft Open Source Code of
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the
[Code of Conduct
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or
comments.
+
+From b3e88fd0eb86d707b343496a62f9bb4e606bb04a Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)gmail.com>
+Date: Fri, 4 May 2018 13:30:03 -0700
+Subject: [PATCH 24/29] Update README.md
+
+---
+ README.md | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/README.md b/README.md
+index dbeaaabc0..d0791d5c8 100644
+--- a/README.md
++++ b/README.md
+@@ -3,18 +3,18 @@ The Reactive Extensions for C++ (__RxCpp__) is a library of algorithms
for value
+ Platform | Status |
+ ----------- | :------------ |
+ Windows | [![Windows
Status](http://img.shields.io/appveyor/ci/kirkshoop/RxCpp-446.svg?style=f...
+-Linux & OSX | [![Linux & Osx
Status](http://img.shields.io/travis/Reactive-Extensions/RxCpp.svg?style=...
++Linux & OSX | [![Linux & Osx
Status](http://img.shields.io/travis/ReactiveX/RxCpp.svg?style=flat-squar...
+
+ Source | Badges |
+ ------------- | :--------------- |
+-Github | [![GitHub
license](https://img.shields.io/github/license/Reactive-Extensions/RxCpp....
<br/> [![GitHub
release](https://img.shields.io/github/release/Reactive-Extensions/RxCpp....
<br/> [![GitHub
commits](https://img.shields.io/github/commits-since/Reactive-Extensions/...
+-Gitter.im | [![Join in on
gitter.im](https://img.shields.io/gitter/room/Reactive-Extensions/RxCpp.svg?style=flat-square)](https://gitter.im/Reactive-Extensions/RxCpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
++Github | [![GitHub
license](https://img.shields.io/github/license/ReactiveX/RxCpp.svg?style=...
<br/> [![GitHub
release](https://img.shields.io/github/release/ReactiveX/RxCpp.svg?style=...
<br/> [![GitHub
commits](https://img.shields.io/github/commits-since/ReactiveX/RxCpp/v4.0...
++Gitter.im | [![Join in on
gitter.im](https://img.shields.io/gitter/room/ReactiveX/RxCpp.svg?style=flat-square)](https://gitter.im/ReactiveX/RxCpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+ Packages | [![NuGet
version](http://img.shields.io/nuget/v/RxCpp.svg?style=flat-square)](http...
[![vcpkg
port](https://img.shields.io/badge/vcpkg-port-blue.svg?style=flat-square)...
+-Documentation | [![rxcpp doxygen
documentation](https://img.shields.io/badge/rxcpp-latest-brightgreen.svg?style=flat-square)](http://reactive-extensions.github.io/RxCpp)
<br/> [![reactivex
intro](https://img.shields.io/badge/reactivex.io-intro-brightgreen.svg?style=flat-square)](http://reactivex.io/intro.html)
[![rx marble
diagrams](https://img.shields.io/badge/rxmarbles-diagrams-brightgreen.svg...
++Documentation | [![rxcpp doxygen
documentation](https://img.shields.io/badge/rxcpp-latest-brightgreen.svg?style=flat-square)](http://reactivex.github.io/RxCpp)
<br/> [![reactivex
intro](https://img.shields.io/badge/reactivex.io-intro-brightgreen.svg?style=flat-square)](http://reactivex.io/intro.html)
[![rx marble
diagrams](https://img.shields.io/badge/rxmarbles-diagrams-brightgreen.svg...
+
+ # Usage
+
+-__RxCpp__ is a header-only C++ library that only depends on the standard library. The
CMake build generates documentation and unit tests.
++__RxCpp__ is a header-only C++ library that only depends on the standard library. The
CMake build generates documentation and unit tests. The unit tests depend on a git
submodule for the [
Catch](https://github.com/philsquared/Catch) library.
+
+ # Example
+ Add `Rx/v2/src` to the include paths
+@@ -128,7 +128,7 @@ Credit [ReactiveX.io](http://reactivex.io/intro.html)
+ ### Other language implementations
+
+ * Java: [
RxJava](https://github.com/ReactiveX/RxJava)
+-* JavaScript: [
RxJS](https://github.com/Reactive-Extensions/RxJS)
++* JavaScript: [
rxjs](https://github.com/ReactiveX/rxjs)
+ * C#: [
Rx.NET](https://github.com/Reactive-Extensions/Rx.NET)
+ * [More..](http://reactivex.io/languages.html)
+
+@@ -148,7 +148,7 @@ Credit [ReactiveX.io](http://reactivex.io/intro.html)
+ RxCpp uses a git submodule (in `ext/catch`) for the excellent
[
Catch](https://github.com/philsquared/Catch) library. The easiest way to ensure that the
submodules are included in the clone is to add `--recursive` in the clone command.
+
+ ```shell
+-git clone --recursive
https://github.com/Reactive-Extensions/RxCpp.git
++git clone --recursive
https://github.com/ReactiveX/RxCpp.git
+ cd RxCpp
+ ```
+
+@@ -224,7 +224,7 @@ Example of by-tag
+
+ # Documentation
+
+-RxCpp uses Doxygen to generate project
[documentation](http://reactive-extensions.github.io/RxCpp).
++RxCpp uses Doxygen to generate project
[documentation](http://reactivex.github.io/RxCpp).
+
+ When Doxygen+Graphviz is installed, CMake creates a special build task named `doc`. It
creates actual documentation and puts it to `projects/doxygen/html/` folder, which can be
published to the `gh-pages` branch. Each merged pull request will build the docs and
publish them.
+
+
+From 533e3a349ac0699c946c5497675ac5d159479030 Mon Sep 17 00:00:00 2001
+From: Kirk Shoop <kirk.shoop(a)gmail.com>
+Date: Fri, 4 May 2018 13:35:33 -0700
+Subject: [PATCH 25/29] Update README.md
+
+---
+ README.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/README.md b/README.md
+index d0791d5c8..3cd4d7af8 100644
+--- a/README.md
++++ b/README.md
+@@ -8,7 +8,7 @@ Linux & OSX | [![Linux & Osx
Status](http://img.shields.io/travis/ReactiveX/RxCp
+ Source | Badges |
+ ------------- | :--------------- |
+ Github | [![GitHub
license](https://img.shields.io/github/license/ReactiveX/RxCpp.svg?style=...
<br/> [![GitHub
release](https://img.shields.io/github/release/ReactiveX/RxCpp.svg?style=...
<br/> [![GitHub
commits](https://img.shields.io/github/commits-since/ReactiveX/RxCpp/v4.0...
+-Gitter.im | [![Join in on
gitter.im](https://img.shields.io/gitter/room/ReactiveX/RxCpp.svg?style=flat-square)](https://gitter.im/ReactiveX/RxCpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
++Gitter.im | [![Join in on
gitter.im](https://img.shields.io/gitter/room/Reactive-Extensions/RxCpp.svg?style=flat-square)](https://gitter.im/ReactiveX/RxCpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+ Packages | [![NuGet
version](http://img.shields.io/nuget/v/RxCpp.svg?style=flat-square)](http...
[![vcpkg
port](https://img.shields.io/badge/vcpkg-port-blue.svg?style=flat-square)...
+ Documentation | [![rxcpp doxygen
documentation](https://img.shields.io/badge/rxcpp-latest-brightgreen.svg?style=flat-square)](http://reactivex.github.io/RxCpp)
<br/> [![reactivex
intro](https://img.shields.io/badge/reactivex.io-intro-brightgreen.svg?style=flat-square)](http://reactivex.io/intro.html)
[![rx marble
diagrams](https://img.shields.io/badge/rxmarbles-diagrams-brightgreen.svg...
+
+
+From 28db2ee9fdac1aed6fa8e360ea5ddf12856d0f6b Mon Sep 17 00:00:00 2001
+From: Andrei Lebedev <lebdron(a)gmail.com>
+Date: Fri, 11 May 2018 00:32:43 +0300
+Subject: [PATCH 26/29] Remove unused variable and captures in
+ doxygen/buffer.cpp
+
+---
+ Rx/v2/examples/doxygen/buffer.cpp | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/Rx/v2/examples/doxygen/buffer.cpp b/Rx/v2/examples/doxygen/buffer.cpp
+index e88c2ed55..58f023a6c 100644
+--- a/Rx/v2/examples/doxygen/buffer.cpp
++++ b/Rx/v2/examples/doxygen/buffer.cpp
+@@ -162,7 +162,6 @@ SCENARIO("buffer period sample"){
+
+ SCENARIO("buffer period+count+coordination sample"){
+ printf("//! [buffer period+count+coordination sample]\n");
+- auto start = std::chrono::steady_clock::now();
+ auto int1 = rxcpp::observable<>::range(1L, 3L);
+ auto int2 = rxcpp::observable<>::timer(std::chrono::milliseconds(50));
+ auto values = int1.
+@@ -171,7 +170,7 @@ SCENARIO("buffer period+count+coordination sample"){
+ values.
+ as_blocking().
+ subscribe(
+- [start](std::vector<long> v){
++ [](std::vector<long> v){
+ printf("OnNext:");
+ std::for_each(v.begin(), v.end(), [](long a){
+ printf(" %ld", a);
+@@ -184,7 +183,6 @@ SCENARIO("buffer period+count+coordination sample"){
+
+ SCENARIO("buffer period+count sample"){
+ printf("//! [buffer period+count sample]\n");
+- auto start = std::chrono::steady_clock::now();
+ auto int1 = rxcpp::observable<>::range(1L, 3L);
+ auto int2 = rxcpp::observable<>::timer(std::chrono::milliseconds(50));
+ auto values = int1.
+@@ -192,7 +190,7 @@ SCENARIO("buffer period+count sample"){
+ buffer_with_time_or_count(std::chrono::milliseconds(20), 2);
+ values.
+ subscribe(
+- [start](std::vector<long> v){
++ [](std::vector<long> v){
+ printf("OnNext:");
+ std::for_each(v.begin(), v.end(), [](long a){
+ printf(" %ld", a);
+
+From abaf9881831d3adf52625443611aa1c3ea5e5dbf Mon Sep 17 00:00:00 2001
+From: Andrei Lebedev <lebdron(a)gmail.com>
+Date: Fri, 11 May 2018 02:08:37 +0300
+Subject: [PATCH 27/29] Fix exit_recursed_scope_type dtor cleaning requestor
+ early
+
+---
+ Rx/v2/src/rxcpp/rx-scheduler.hpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/rx-scheduler.hpp b/Rx/v2/src/rxcpp/rx-scheduler.hpp
+index 0f239be73..8bdb4dd4e 100644
+--- a/Rx/v2/src/rxcpp/rx-scheduler.hpp
++++ b/Rx/v2/src/rxcpp/rx-scheduler.hpp
+@@ -480,9 +480,9 @@ class schedulable : public schedulable_base
+ // no change in recursion scope
+ return *this;
+ }
+- exit_recursed_scope_type reset(const recurse& r) const {
++ std::shared_ptr<exit_recursed_scope_type> reset(const recurse& r)
const {
+ requestor = std::addressof(r.get_recursed());
+- return exit_recursed_scope_type(this);
++ return std::make_shared<exit_recursed_scope_type>(this);
+ }
+ bool is_recursed() const {
+ return !!requestor;
+
+From c7de35be5dc31785984f9b3c6b21f7bf46a05034 Mon Sep 17 00:00:00 2001
+From: Andrei Lebedev <lebdron(a)gmail.com>
+Date: Fri, 11 May 2018 08:22:09 +0300
+Subject: [PATCH 28/29] Replace shared_ptr with move ctor
+
+---
+ Rx/v2/src/rxcpp/rx-scheduler.hpp | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/Rx/v2/src/rxcpp/rx-scheduler.hpp b/Rx/v2/src/rxcpp/rx-scheduler.hpp
+index 8bdb4dd4e..dbf6cb256 100644
+--- a/Rx/v2/src/rxcpp/rx-scheduler.hpp
++++ b/Rx/v2/src/rxcpp/rx-scheduler.hpp
+@@ -458,12 +458,19 @@ class schedulable : public schedulable_base
+ public:
+ ~exit_recursed_scope_type()
+ {
++ if (that != nullptr) {
+ that->requestor = nullptr;
++ }
+ }
+ exit_recursed_scope_type(const recursed_scope_type* that)
+ : that(that)
+ {
+ }
++ exit_recursed_scope_type(exit_recursed_scope_type && other)
/*noexcept*/
++ : that(other.that)
++ {
++ other.that = nullptr;
++ }
+ };
+ public:
+ recursed_scope_type()
+@@ -480,9 +487,9 @@ class schedulable : public schedulable_base
+ // no change in recursion scope
+ return *this;
+ }
+- std::shared_ptr<exit_recursed_scope_type> reset(const recurse& r)
const {
++ exit_recursed_scope_type reset(const recurse& r) const {
+ requestor = std::addressof(r.get_recursed());
+- return std::make_shared<exit_recursed_scope_type>(this);
++ return exit_recursed_scope_type(this);
+ }
+ bool is_recursed() const {
+ return !!requestor;
+
+From eaf0545efef9fdccc0a6bc88f23ef0fc876c36f3 Mon Sep 17 00:00:00 2001
+From: Andrei Lebedev <lebdron(a)gmail.com>
+Date: Fri, 11 May 2018 08:23:22 +0300
+Subject: [PATCH 29/29] Replace commented out noexcept with macro
+
+---
+ Rx/v2/src/rxcpp/rx-scheduler.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Rx/v2/src/rxcpp/rx-scheduler.hpp b/Rx/v2/src/rxcpp/rx-scheduler.hpp
+index dbf6cb256..fc689793b 100644
+--- a/Rx/v2/src/rxcpp/rx-scheduler.hpp
++++ b/Rx/v2/src/rxcpp/rx-scheduler.hpp
+@@ -466,7 +466,7 @@ class schedulable : public schedulable_base
+ : that(that)
+ {
+ }
+- exit_recursed_scope_type(exit_recursed_scope_type && other)
/*noexcept*/
++ exit_recursed_scope_type(exit_recursed_scope_type && other)
RXCPP_NOEXCEPT
+ : that(other.that)
+ {
+ other.that = nullptr;
diff --git a/RxCpp.spec b/RxCpp.spec
new file mode 100644
index 0000000..51f8e39
--- /dev/null
+++ b/RxCpp.spec
@@ -0,0 +1,152 @@
+# Header only lib. Package is build archful to run the tests
+# on all available architectures, thus we disable debug packages.
+%global debug_package %{nil}
+
+# Setup _pkgdocdir if not defined already.
+%{!?_pkgdocdir:%global _pkgdocdir %{_docdir}/%{name}-%{version}}
+
+# Package name in lowercase. %%global won't work here.
+%define lc_name %{lua:print(rpm.expand("%{name}"):lower())}
+
+
+Name: RxCpp
+Version: 4.0.0
+Release: 1%{?dist}
+Summary: Reactive Extensions for C++
+
+License: ASL 2.0
+URL:
https://github.com/Reactive-Extensions/%{name}
+Source0: %{url}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
+
+# 0 - 999: Cherry-picked from upstream.
+Patch0: %{url}/compare/v4.0.0...master.patch#/%{name}-4.0.0-to_master.patch
+
+# 1000 - 1999: Upstreamed.
+
+# 2000 - 2999: Upstreamable.
+
+# 3000 - 3999: Downstream / not upstreamable.
+
+BuildRequires: catch-devel
+BuildRequires: cmake3
+BuildRequires: gcc-c++
+
+%description
+The Reactive Extensions for C++ (RxCpp) is a library of algorithms
+for values-distributed-in-time.
+
+
+%package devel
+Summary: Reactive Extensions for C++
+BuildArch: noarch
+
+Provides: %{name} == %{version}-%{release}
+Provides: %{name}-static == %{version}-%{release}
+Provides: %{lc_name} == %{version}-%{release}
+Provides: %{lc_name}-devel == %{version}-%{release}
+Provides: %{lc_name}-static == %{version}-%{release}
+
+%description devel
+The Reactive Extensions for C++ (RxCpp) is a library of algorithms
+for values-distributed-in-time.
+
+
+%package doc
+Summary: API-documentation for %{name}
+BuildArch: noarch
+
+BuildRequires: doxygen
+BuildRequires: graphviz
+BuildRequires: hardlink
+
+Provides: %{lc_name}-doc == %{version}-%{release}
+
+%description doc
+This package contains the API-documentation for %{name}.
+
+
+%prep
+%autosetup -p 1
+
+# Rename toplevel license file.
+%{__mv} license.md ASL-2.0.txt
+
+# Fix path to catch.
+%{__sed} -i.catch -e 's!\${RXCPP_DIR}/ext/catch/include!%{_includedir}/catch!g'
\
+ projects/CMake/shared.cmake
+
+
+%build
+%cmake3 -DCMAKE_BUILD_TYPE=Release .
+
+# Builds needs about 2.5 GiB of RAM per thread on x86_64,
+# on certain other arches even more. Thus building with
+# less threads on %%{power64}.
+%ifnarch %{power64}
+%make_build
+%else
+%{__make} -O -j2
+%endif
+
+# Build docs.
+pushd projects/doxygen
+%{_bindir}/doxygen doxygen.conf
+popd
+
+
+%install
+%make_install
+
+# Install docs.
+%{__mkdir_p} %{buildroot}%{_pkgdocdir}
+%{__cp} -pr DeveloperManual.md README.md Readme.html \
+%if 0%{?rhel} && 0%{?rhel} <= 6
+ AUTHORS.txt ASL-2.0.txt Rx/v2/license.txt \
+%endif
+ projects/doxygen/html %{buildroot}%{_pkgdocdir}
+%{_bindir}/find %{buildroot}%{_pkgdocdir} -type f | \
+ %{_bindir}/xargs %{__chmod} -c 0644
+%{_bindir}/find %{buildroot}%{_pkgdocdir} -type d | \
+ %{_bindir}/xargs %{__chmod} -c 0755
+%{_sbindir}/hardlink -fv %{buildroot}%{_pkgdocdir}
+
+
+%check
+# Checks are run single-threaded on purpose, because they may
+# exhaust memory of Koji workers otherwise. The timeout is set
+# to be a day for preventing them to time out to soon on Koji.
+pushd build/test
+%{_bindir}/ctest3 %{?_smp_mflags} -V --timeout 86400
+popd
+
+
+%files devel
+%if 0%{?fedora} || 0%{?rhel} >= 7
+%license AUTHORS.txt
+%license ASL-2.0.txt
+%license Rx/v2/license.txt
+%else
+%doc %{_pkgdocdir}/AUTHORS.txt
+%doc %{_pkgdocdir}/ASL-2.0.txt
+%doc %{_pkgdocdir}/license.txt
+%endif
+%doc %dir %{_pkgdocdir}
+%doc %{_pkgdocdir}/DeveloperManual.md
+%doc %{_pkgdocdir}/README.md
+%doc %{_pkgdocdir}/Readme.html
+%{_includedir}/%{lc_name}
+
+
+%files doc
+%if 0%{?fedora} || 0%{?rhel} >= 7
+%license %{_datadir}/licenses/%{name}-devel*
+%endif
+%doc %{_pkgdocdir}
+
+
+%changelog
+* Fri May 18 2018 Björn Esser <besser82(a)fedoraproject.org> - 4.0.0-1
+- Initial import (rhbz#1579523)
+
+* Wed May 02 2018 Björn Esser <besser82(a)fedoraproject.org> - 4.0.0-0.1
+- Initial rpm release (rhbz#1579523)
diff --git a/sources b/sources
new file mode 100644
index 0000000..1c10588
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (RxCpp-4.0.0.tar.gz) =
df7582925e749fb7f9fbc085566d57a46571e18202aacaa7d35cf9da8152b29dd2886b2d07dae93e538f2a0f7b91d93fb3da23c34c7ea4467772515c794a25b7