diff options
author | iam <igor.murashkin+github@gmail.com> | 2018-10-27 13:12:45 -0700 |
---|---|---|
committer | Kirk Shoop <kirk.shoop@gmail.com> | 2018-10-27 13:12:45 -0700 |
commit | 4aa52e42579cbd9e2cef6c0a6c2b0d8edf73ac5d (patch) | |
tree | 2b4a574fcd4a62d8b59174646b76c53fa9c15b2d | |
parent | ed3fe6418276781e662e5113ee3cee1bee4f0998 (diff) | |
download | RxCpp-4aa52e42579cbd9e2cef6c0a6c2b0d8edf73ac5d.tar.gz |
Add support for compiling rxcpp with -fno-exceptions (#456)
* Minor compilation/test fixes for compiling on android
Change-Id: Id623455d32e9323355744a240c2813d0411d1dac
* Rx: Add support for compiling code without exceptions (-fno-exceptions)
std::exception_ptr usage is replaced with rxcpp::util::error_ptr
which will typedef to std::exception_ptr when exceptions are enabled.
When exceptions are disabled this will typedef to an internal error
type that can retain the "what" error message.
Additionally std::current_exception() and similar usages are replaced
with rxu::current_exception which uses error_ptr instead.
Lastly all try/catch/throw keywords are replaced with either
RXCPP_TRY, RXCPP_CATCH, rxu::throw_exception or similar.
Note that try/catch/throw keywords cause a compilation error with
-fno-exceptions. Trying to access most of the std::*exception* functions
will call std::terminate at runtime.
Tests using exceptions must be disabled by passing --nothrow to the
check2 test runner.
Change-Id: I0b95ae2e323653a17c3b733d165ecf87a014c315
* update to catch2 and add RX_USE_EXCEPTIONS cmake option
* fix bugs in doxygen examples
* replace [[noreturn]] with RXCPP_NORETURN
* removes support for VS 2013
105 files changed, 577 insertions, 323 deletions
diff --git a/.travis.yml b/.travis.yml index 20a2197..daa4800 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,15 +10,15 @@ env: matrix: include: - - env: BUILD_TYPE=Debug ASAN=Off RUN_TEST=On + - env: BUILD_TYPE=Debug ASAN=Off RUN_TEST=On EXCEPTIONS=On os: osx osx_image: xcode8 - - env: BUILD_TYPE=Debug ASAN=Off LLVM_VERSION=3.8.0 RUN_TEST=On + - env: BUILD_TYPE=Debug ASAN=Off LLVM_VERSION=3.8.0 RUN_TEST=On EXCEPTIONS=On os: linux compiler: clang - - env: BUILD_TYPE=Release ASAN=Off GCC_VERSION=4.9 RUN_TEST=On + - env: BUILD_TYPE=Release ASAN=Off GCC_VERSION=4.9 RUN_TEST=On EXCEPTIONS=On os: linux compiler: gcc addons: @@ -28,7 +28,37 @@ matrix: sources: - ubuntu-toolchain-r-test - - env: BUILD_TYPE=Debug ASAN=Off LLVM_VERSION=3.8.0 RUN_TEST=Off PROJECT=doc PUBLISH_DOCS=On DOXYGEN_VERSION=1.8.11 + - env: BUILD_TYPE=Release ASAN=Off GCC_VERSION=7 RUN_TEST=On EXCEPTIONS=On + os: linux + compiler: gcc + addons: &gcc7 + apt: + packages: + - g++-7 + sources: + - ubuntu-toolchain-r-test + + - env: BUILD_TYPE=RelWithDebInfo ASAN=Off GCC_VERSION=8 RUN_TEST=On EXCEPTIONS=Off + os: linux + compiler: gcc + addons: &gcc8 + apt: + packages: + - g++-8 + sources: + - ubuntu-toolchain-r-test + + - env: BUILD_TYPE=Release ASAN=Off GCC_VERSION=8 RUN_TEST=On EXCEPTIONS=On + os: linux + compiler: gcc + addons: &gcc8 + apt: + packages: + - g++-8 + sources: + - ubuntu-toolchain-r-test + + - env: BUILD_TYPE=Debug ASAN=Off LLVM_VERSION=3.8.0 RUN_TEST=Off EXCEPTIONS=On PROJECT=doc PUBLISH_DOCS=On DOXYGEN_VERSION=1.8.11 os: linux compiler: clang addons: @@ -127,6 +157,9 @@ before_script: if [ -z "$BUILD_TYPE" ]; then BUILD_TYPE=Release; fi; + if [ -z "$EXCEPTIONS" ]; then + EXCEPTIONS=On; + fi; if [[ "${ASAN}" == "On" ]]; then export CXXFLAGS="${CXXFLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow"; fi; @@ -138,7 +171,7 @@ before_script: # generate build ############################################################################ - cd ${TRAVIS_BUILD_DIR} - - cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE + - cmake . -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DRX_USE_EXCEPTIONS=${EXCEPTIONS} script: ############################################################################ diff --git a/Rx/v2/examples/doxygen/composite_exception.cpp b/Rx/v2/examples/doxygen/composite_exception.cpp index 697b83f..6cbfce3 100644 --- a/Rx/v2/examples/doxygen/composite_exception.cpp +++ b/Rx/v2/examples/doxygen/composite_exception.cpp @@ -4,6 +4,7 @@ namespace rxu=rxcpp::util; #include "rxcpp/rx-test.hpp" #include "catch.hpp" +#if RXCPP_USE_EXCEPTIONS SCENARIO("composite_exception sample"){ printf("//! [composite_exception sample]\n"); auto o1 = rxcpp::observable<>::error<int>(std::runtime_error("Error from source o1\n")); @@ -29,3 +30,4 @@ SCENARIO("composite_exception sample"){ ); printf("//! [composite_exception sample]\n"); } +#endif diff --git a/Rx/v2/examples/doxygen/create.cpp b/Rx/v2/examples/doxygen/create.cpp index f8d024f..1f707c6 100644 --- a/Rx/v2/examples/doxygen/create.cpp +++ b/Rx/v2/examples/doxygen/create.cpp @@ -90,11 +90,8 @@ SCENARIO("Create great code"){ [](int v){ printf("OnNext: %d\n", v); }, - [](std::exception_ptr ep){ - try {std::rethrow_exception(ep);} - catch (const std::exception& ex) { - printf("OnError: %s\n", ex.what()); - } + [](rxcpp::util::error_ptr ep){ + printf("OnError: %s\n", rxcpp::util::what(ep).c_str()); }, [](){ printf("OnCompleted\n"); diff --git a/Rx/v2/examples/doxygen/error.cpp b/Rx/v2/examples/doxygen/error.cpp index 8d5b000..87b5b78 100644 --- a/Rx/v2/examples/doxygen/error.cpp +++ b/Rx/v2/examples/doxygen/error.cpp @@ -9,11 +9,8 @@ SCENARIO("error sample"){ values. subscribe( [](int v){printf("OnNext: %d\n", v);}, - [](std::exception_ptr ep){ - try {std::rethrow_exception(ep);} - catch (const std::exception& ex) { - printf("OnError: %s\n", ex.what()); - } + [](rxcpp::util::error_ptr ep){ + printf("OnError: %s\n", rxcpp::util::what(ep).c_str()); }, [](){printf("OnCompleted\n");}); printf("//! [error sample]\n"); @@ -26,11 +23,8 @@ SCENARIO("threaded error sample"){ as_blocking(). subscribe( [](int v){printf("OnNext: %d\n", v);}, - [](std::exception_ptr ep){ - try {std::rethrow_exception(ep);} - catch (const std::exception& ex) { - printf("OnError: %s\n", ex.what()); - } + [](rxcpp::util::error_ptr ep){ + printf("OnError: %s\n", rxcpp::util::what(ep).c_str()); }, [](){printf("OnCompleted\n");}); printf("//! [threaded error sample]\n"); diff --git a/Rx/v2/examples/doxygen/finally.cpp b/Rx/v2/examples/doxygen/finally.cpp index 3f25196..253d3a9 100644 --- a/Rx/v2/examples/doxygen/finally.cpp +++ b/Rx/v2/examples/doxygen/finally.cpp @@ -26,11 +26,8 @@ SCENARIO("error finally sample"){ values. subscribe( [](int v){printf("OnNext: %d\n", v);}, - [](std::exception_ptr ep){ - try {std::rethrow_exception(ep);} - catch (const std::exception& ex) { - printf("OnError: %s\n", ex.what()); - } + [](rxcpp::util::error_ptr ep){ + printf("OnError: %s\n", rxcpp::util::what(ep).c_str()); }, [](){printf("OnCompleted\n");}); printf("//! [error finally sample]\n"); diff --git a/Rx/v2/examples/doxygen/group_by.cpp b/Rx/v2/examples/doxygen/group_by.cpp index b716d6f..74ef859 100644 --- a/Rx/v2/examples/doxygen/group_by.cpp +++ b/Rx/v2/examples/doxygen/group_by.cpp @@ -3,6 +3,8 @@ #include "rxcpp/rx-test.hpp" #include "catch.hpp" +#include <sstream> + SCENARIO("group_by sample"){ printf("//! [group_by sample]\n"); auto values = rxcpp::observable<>::range(0, 8). diff --git a/Rx/v2/examples/doxygen/math.cpp b/Rx/v2/examples/doxygen/math.cpp index 376cf97..d430953 100644 --- a/Rx/v2/examples/doxygen/math.cpp +++ b/Rx/v2/examples/doxygen/math.cpp @@ -13,6 +13,7 @@ SCENARIO("first sample"){ printf("//! [first sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("first empty sample"){ printf("//! [first empty sample]\n"); auto values = rxcpp::observable<>::empty<int>().first(); @@ -28,6 +29,7 @@ SCENARIO("first empty sample"){ [](){printf("OnCompleted\n");}); printf("//! [first empty sample]\n"); } +#endif SCENARIO("last sample"){ printf("//! [last sample]\n"); @@ -39,6 +41,7 @@ SCENARIO("last sample"){ printf("//! [last sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("last empty sample"){ printf("//! [last empty sample]\n"); auto values = rxcpp::observable<>::empty<int>().last(); @@ -54,6 +57,7 @@ SCENARIO("last empty sample"){ [](){printf("OnCompleted\n");}); printf("//! [last empty sample]\n"); } +#endif SCENARIO("count sample"){ printf("//! [count sample]\n"); @@ -65,6 +69,7 @@ SCENARIO("count sample"){ printf("//! [count sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("count error sample"){ printf("//! [count error sample]\n"); auto values = rxcpp::observable<>::range(1, 3). @@ -82,6 +87,7 @@ SCENARIO("count error sample"){ [](){printf("OnCompleted\n");}); printf("//! [count error sample]\n"); } +#endif SCENARIO("sum sample"){ printf("//! [sum sample]\n"); @@ -93,6 +99,7 @@ SCENARIO("sum sample"){ printf("//! [sum sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("sum empty sample"){ printf("//! [sum empty sample]\n"); auto values = rxcpp::observable<>::empty<int>().sum(); @@ -108,6 +115,7 @@ SCENARIO("sum empty sample"){ [](){printf("OnCompleted\n");}); printf("//! [sum empty sample]\n"); } +#endif SCENARIO("sum error sample"){ printf("//! [sum error sample]\n"); @@ -137,6 +145,7 @@ SCENARIO("average sample"){ printf("//! [average sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("average empty sample"){ printf("//! [average empty sample]\n"); auto values = rxcpp::observable<>::empty<int>().average(); @@ -152,6 +161,7 @@ SCENARIO("average empty sample"){ [](){printf("OnCompleted\n");}); printf("//! [average empty sample]\n"); } +#endif SCENARIO("average error sample"){ printf("//! [average error sample]\n"); @@ -181,6 +191,7 @@ SCENARIO("max sample"){ printf("//! [max sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("max empty sample"){ printf("//! [max empty sample]\n"); auto values = rxcpp::observable<>::empty<int>().max(); @@ -196,6 +207,7 @@ SCENARIO("max empty sample"){ [](){printf("OnCompleted\n");}); printf("//! [max empty sample]\n"); } +#endif SCENARIO("max error sample"){ printf("//! [max error sample]\n"); @@ -225,6 +237,7 @@ SCENARIO("min sample"){ printf("//! [min sample]\n"); } +#if RXCPP_USE_EXCEPTIONS SCENARIO("min empty sample"){ printf("//! [min empty sample]\n"); auto values = rxcpp::observable<>::empty<int>().min(); @@ -240,6 +253,7 @@ SCENARIO("min empty sample"){ [](){printf("OnCompleted\n");}); printf("//! [min empty sample]\n"); } +#endif SCENARIO("min error sample"){ printf("//! [min error sample]\n"); diff --git a/Rx/v2/examples/doxygen/merge_delay_error.cpp b/Rx/v2/examples/doxygen/merge_delay_error.cpp index 7a94570..ae75926 100644 --- a/Rx/v2/examples/doxygen/merge_delay_error.cpp +++ b/Rx/v2/examples/doxygen/merge_delay_error.cpp @@ -4,6 +4,8 @@ namespace rxu=rxcpp::util; #include "rxcpp/rx-test.hpp" #include "catch.hpp" +#include <sstream> + SCENARIO("merge_delay_error sample"){ printf("//! [merge_delay_error sample]\n"); auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(15)).map([](int) {return 1;}); @@ -38,19 +40,19 @@ SCENARIO("implicit merge_delay_error sample"){ 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) { + auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(10)).map([](long) -> long { printf("[thread %s] Timer1 fired\n", get_pid().c_str()); return 1; }); - auto o2 = rxcpp::observable<>::timer(std::chrono::milliseconds(20)).flat_map([](int) { + auto o2 = rxcpp::observable<>::timer(std::chrono::milliseconds(20)).flat_map([](long) -> rxcpp::observable<long> { 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())); + return rxcpp::observable<>::error<long>(std::runtime_error(ss.str())); }); - auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(30)).map([](int) { + auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(30)).map([](long) -> long { printf("[thread %s] Timer3 fired\n", get_pid().c_str()); return 3; }); @@ -68,19 +70,19 @@ SCENARIO("threaded merge_delay_error sample"){ 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) { + auto o1 = rxcpp::observable<>::timer(std::chrono::milliseconds(10)).map([](long) -> long { printf("[thread %s] Timer1 fired\n", get_pid().c_str()); return 1; }); - auto o2 = rxcpp::observable<>::timer(std::chrono::milliseconds(20)).flat_map([](int) { + auto o2 = rxcpp::observable<>::timer(std::chrono::milliseconds(20)).flat_map([](long) -> rxcpp::observable<long> { 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())); + return rxcpp::observable<>::error<long>(std::runtime_error(ss.str())); }); - auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(30)).map([](int) { + auto o3 = rxcpp::observable<>::timer(std::chrono::milliseconds(30)).map([](long) -> long { printf("[thread %s] Timer3 fired\n", get_pid().c_str()); return 3; }); @@ -89,7 +91,7 @@ SCENARIO("threaded implicit merge_delay_error sample"){ values. as_blocking(). subscribe( - [](int v){printf("[thread %s] OnNext: %d\n", get_pid().c_str(), v);}, + [](long v){printf("[thread %s] OnNext: %ld\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()); diff --git a/Rx/v2/src/rxcpp/operators/rx-all.hpp b/Rx/v2/src/rxcpp/operators/rx-all.hpp index 65bec46..a0f6a3e 100644 --- a/Rx/v2/src/rxcpp/operators/rx-all.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-all.hpp @@ -83,7 +83,7 @@ struct all dest.on_completed(); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-amb.hpp b/Rx/v2/src/rxcpp/operators/rx-amb.hpp index 595dc4d..56bfbe9 100644 --- a/Rx/v2/src/rxcpp/operators/rx-amb.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-amb.hpp @@ -183,7 +183,7 @@ struct amb } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, //on_completed @@ -196,7 +196,7 @@ struct amb selectedSource.subscribe(std::move(selectedSinkInner)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-any.hpp b/Rx/v2/src/rxcpp/operators/rx-any.hpp index 4488375..19fca6e 100644 --- a/Rx/v2/src/rxcpp/operators/rx-any.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-any.hpp @@ -90,7 +90,7 @@ struct any dest.on_completed(); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-buffer_count.hpp b/Rx/v2/src/rxcpp/operators/rx-buffer_count.hpp index a4dea3b..79eb30e 100644 --- a/Rx/v2/src/rxcpp/operators/rx-buffer_count.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-buffer_count.hpp @@ -96,7 +96,7 @@ struct buffer_count chunks.pop_front(); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-buffer_time.hpp b/Rx/v2/src/rxcpp/operators/rx-buffer_time.hpp index 7e54eb8..aa94f7b 100644 --- a/Rx/v2/src/rxcpp/operators/rx-buffer_time.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-buffer_time.hpp @@ -197,7 +197,7 @@ struct buffer_with_time } localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&){ localState->dest.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-buffer_time_count.hpp b/Rx/v2/src/rxcpp/operators/rx-buffer_time_count.hpp index 346a6ef..6d4b9a4 100644 --- a/Rx/v2/src/rxcpp/operators/rx-buffer_time_count.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-buffer_time_count.hpp @@ -179,7 +179,7 @@ struct buffer_with_time_or_count } localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&){ localState->dest.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-combine_latest.hpp b/Rx/v2/src/rxcpp/operators/rx-combine_latest.hpp index 0f94fde..06ff3d1 100644 --- a/Rx/v2/src/rxcpp/operators/rx-combine_latest.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-combine_latest.hpp @@ -173,7 +173,7 @@ struct combine_latest : public operator_base<rxu::value_type_t<combine_latest_tr } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-concat.hpp b/Rx/v2/src/rxcpp/operators/rx-concat.hpp index 57b42fa..457b9cf 100644 --- a/Rx/v2/src/rxcpp/operators/rx-concat.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-concat.hpp @@ -143,7 +143,7 @@ struct concat state->out.on_next(ct); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, //on_completed @@ -207,7 +207,7 @@ struct concat } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-concat_map.hpp b/Rx/v2/src/rxcpp/operators/rx-concat_map.hpp index edcdb26..546c1eb 100644 --- a/Rx/v2/src/rxcpp/operators/rx-concat_map.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-concat_map.hpp @@ -183,7 +183,7 @@ struct concat_map state->out.on_next(std::move(selectedResult)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, //on_completed @@ -246,7 +246,7 @@ struct concat_map } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-debounce.hpp b/Rx/v2/src/rxcpp/operators/rx-debounce.hpp index 5f56ff9..6fbedd7 100644 --- a/Rx/v2/src/rxcpp/operators/rx-debounce.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-debounce.hpp @@ -158,7 +158,7 @@ struct debounce localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&) { localState->dest.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-delay.hpp b/Rx/v2/src/rxcpp/operators/rx-delay.hpp index 19bbed5..5986f79 100644 --- a/Rx/v2/src/rxcpp/operators/rx-delay.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-delay.hpp @@ -131,7 +131,7 @@ struct delay localState->worker.schedule(localState->worker.now() + localState->period, selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&){ localState->dest.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-distinct.hpp b/Rx/v2/src/rxcpp/operators/rx-distinct.hpp index c3ca086..c90ebdb 100644 --- a/Rx/v2/src/rxcpp/operators/rx-distinct.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-distinct.hpp @@ -61,7 +61,7 @@ struct distinct dest.on_next(v); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-distinct_until_changed.hpp b/Rx/v2/src/rxcpp/operators/rx-distinct_until_changed.hpp index 7d8ef5a..3702185 100644 --- a/Rx/v2/src/rxcpp/operators/rx-distinct_until_changed.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-distinct_until_changed.hpp @@ -74,7 +74,7 @@ struct distinct_until_changed dest.on_next(v); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-element_at.hpp b/Rx/v2/src/rxcpp/operators/rx-element_at.hpp index 5cbe6dc..1d773ac 100644 --- a/Rx/v2/src/rxcpp/operators/rx-element_at.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-element_at.hpp @@ -77,12 +77,12 @@ struct element_at { dest.on_completed(); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { if(current <= this->index) { - dest.on_error(std::make_exception_ptr(std::range_error("index is out of bounds"))); + dest.on_error(rxu::make_error_ptr(std::range_error("index is out of bounds"))); } } diff --git a/Rx/v2/src/rxcpp/operators/rx-filter.hpp b/Rx/v2/src/rxcpp/operators/rx-filter.hpp index 86ce649..3a622bb 100644 --- a/Rx/v2/src/rxcpp/operators/rx-filter.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-filter.hpp @@ -79,7 +79,7 @@ struct filter dest.on_next(std::forward<Value>(v)); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-finally.hpp b/Rx/v2/src/rxcpp/operators/rx-finally.hpp index 4e4416c..d6f5487 100644 --- a/Rx/v2/src/rxcpp/operators/rx-finally.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-finally.hpp @@ -70,7 +70,7 @@ struct finally void on_next(source_value_type v) const { dest.on_next(v); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-flat_map.hpp b/Rx/v2/src/rxcpp/operators/rx-flat_map.hpp index 5b68b37..eb76198 100644 --- a/Rx/v2/src/rxcpp/operators/rx-flat_map.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-flat_map.hpp @@ -198,7 +198,7 @@ struct flat_map state->out.on_next(std::move(selectedResult)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, //on_completed @@ -213,7 +213,7 @@ struct flat_map selectedSource.subscribe(std::move(selectedSinkInner)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-group_by.hpp b/Rx/v2/src/rxcpp/operators/rx-group_by.hpp index 8b451e5..d1c4ea4 100644 --- a/Rx/v2/src/rxcpp/operators/rx-group_by.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-group_by.hpp @@ -200,7 +200,7 @@ struct group_by auto selectedKey = on_exception( [&](){ return this->keySelector(v);}, - [this](std::exception_ptr e){on_error(e);}); + [this](rxu::error_ptr e){on_error(e);}); if (selectedKey.empty()) { return; } @@ -215,7 +215,7 @@ struct group_by auto durationObs = on_exception( [&](){ return this->durationSelector(obs);}, - [this](std::exception_ptr e){on_error(e);}); + [this](rxu::error_ptr e){on_error(e);}); if (durationObs.empty()) { return; } @@ -237,20 +237,20 @@ struct group_by auto robs = durationObs.get().take(1); duration_sub.add(robs.subscribe( [](const typename decltype(robs)::value_type &){}, - [=](std::exception_ptr ) {expire();}, + [=](rxu::error_ptr) {expire();}, [=](){expire();} )); } auto selectedMarble = on_exception( [&](){ return this->marbleSelector(v);}, - [this](std::exception_ptr e){on_error(e);}); + [this](rxu::error_ptr e){on_error(e);}); if (selectedMarble.empty()) { return; } g->second.on_next(std::move(selectedMarble.get())); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { for(auto& g : state->groups) { g.second.on_error(e); } diff --git a/Rx/v2/src/rxcpp/operators/rx-ignore_elements.hpp b/Rx/v2/src/rxcpp/operators/rx-ignore_elements.hpp index 82fbe95..00b10a6 100644 --- a/Rx/v2/src/rxcpp/operators/rx-ignore_elements.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-ignore_elements.hpp @@ -56,7 +56,7 @@ struct ignore_elements { // no-op; ignore element } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } diff --git a/Rx/v2/src/rxcpp/operators/rx-map.hpp b/Rx/v2/src/rxcpp/operators/rx-map.hpp index a670d88..7570376 100644 --- a/Rx/v2/src/rxcpp/operators/rx-map.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-map.hpp @@ -77,7 +77,7 @@ struct map } dest.on_next(std::move(selected.get())); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-merge.hpp b/Rx/v2/src/rxcpp/operators/rx-merge.hpp index ad8f7d0..cc1ea77 100644 --- a/Rx/v2/src/rxcpp/operators/rx-merge.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-merge.hpp @@ -173,7 +173,7 @@ struct merge state->out.on_next(std::move(ct)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, //on_completed @@ -188,7 +188,7 @@ struct merge selectedSource.subscribe(std::move(selectedSinkInner)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp b/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp index 43fdee3..51f8867 100644 --- a/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-merge_delay_error.hpp @@ -167,10 +167,10 @@ struct merge_delay_error state->out.on_next(std::move(ct)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { if(--state->pendingCompletions == 0) { state->out.on_error( - std::make_exception_ptr(std::move(state->exception.add(e)))); + rxu::make_error_ptr(std::move(state->exception.add(e)))); } else { state->exception.add(e); } @@ -180,7 +180,7 @@ struct merge_delay_error if (--state->pendingCompletions == 0) { if(!state->exception.empty()) { state->out.on_error( - std::make_exception_ptr(std::move(state->exception))); + rxu::make_error_ptr(std::move(state->exception))); } else { state->out.on_completed(); } @@ -192,10 +192,10 @@ struct merge_delay_error selectedSource.subscribe(std::move(selectedSinkInner)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { if(--state->pendingCompletions == 0) { state->out.on_error( - std::make_exception_ptr(std::move(state->exception.add(e)))); + rxu::make_error_ptr(std::move(state->exception.add(e)))); } else { state->exception.add(e); } @@ -205,7 +205,7 @@ struct merge_delay_error if (--state->pendingCompletions == 0) { if(!state->exception.empty()) { state->out.on_error( - std::make_exception_ptr(std::move(state->exception))); + rxu::make_error_ptr(std::move(state->exception))); } else { state->out.on_completed(); } diff --git a/Rx/v2/src/rxcpp/operators/rx-observe_on.hpp b/Rx/v2/src/rxcpp/operators/rx-observe_on.hpp index 274f3f1..b50b773 100644 --- a/Rx/v2/src/rxcpp/operators/rx-observe_on.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-observe_on.hpp @@ -127,7 +127,7 @@ struct observe_on auto drain = [keepAlive, this](const rxsc::schedulable& self){ using std::swap; - try { + RXCPP_TRY { for (;;) { if (drain_queue.empty() || !destination.is_subscribed()) { std::unique_lock<std::mutex> guard(lock); @@ -151,8 +151,9 @@ struct observe_on self(); if (lifetime.is_subscribed()) break; } - } catch(...) { - destination.on_error(std::current_exception()); + } + RXCPP_CATCH(...) { + destination.on_error(rxu::current_exception()); std::unique_lock<std::mutex> guard(lock); finish(guard, mode::Errored); } @@ -188,7 +189,7 @@ struct observe_on state->fill_queue.push_back(notification_type::on_next(std::move(v))); state->ensure_processing(guard); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { std::unique_lock<std::mutex> guard(state->lock); if (state->current == mode::Errored || state->current == mode::Disposed) { return; } state->fill_queue.push_back(notification_type::on_error(e)); diff --git a/Rx/v2/src/rxcpp/operators/rx-on_error_resume_next.hpp b/Rx/v2/src/rxcpp/operators/rx-on_error_resume_next.hpp index 4ebee38..bc9beba 100644 --- a/Rx/v2/src/rxcpp/operators/rx-on_error_resume_next.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-on_error_resume_next.hpp @@ -6,9 +6,9 @@ \brief If an error occurs, take the result from the Selector and subscribe to that instead. - \tparam Selector the actual type of a function of the form `observable<T>(std::exception_ptr)` + \tparam Selector the actual type of a function of the form `observable<T>(rxu::error_ptr)` - \param s the function of the form `observable<T>(std::exception_ptr)` + \param s the function of the form `observable<T>(rxu::error_ptr)` \return Observable that emits the items from the source observable and switches to a new observable on error. @@ -44,7 +44,7 @@ struct on_error_resume_next { typedef rxu::decay_t<T> value_type; typedef rxu::decay_t<Selector> select_type; - typedef decltype((*(select_type*)nullptr)(std::exception_ptr())) fallback_type; + typedef decltype((*(select_type*)nullptr)(rxu::error_ptr())) fallback_type; select_type selector; on_error_resume_next(select_type s) @@ -58,7 +58,7 @@ struct on_error_resume_next typedef on_error_resume_next_observer<Subscriber> this_type; typedef rxu::decay_t<T> value_type; typedef rxu::decay_t<Selector> select_type; - typedef decltype((*(select_type*)nullptr)(std::exception_ptr())) fallback_type; + typedef decltype((*(select_type*)nullptr)(rxu::error_ptr())) fallback_type; typedef rxu::decay_t<Subscriber> dest_type; typedef observer<T, this_type> observer_type; dest_type dest; @@ -75,7 +75,7 @@ struct on_error_resume_next void on_next(value_type v) const { dest.on_next(std::move(v)); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto selected = on_exception( [&](){ return this->selector(std::move(e));}, diff --git a/Rx/v2/src/rxcpp/operators/rx-pairwise.hpp b/Rx/v2/src/rxcpp/operators/rx-pairwise.hpp index 584a6bf..411cf27 100644 --- a/Rx/v2/src/rxcpp/operators/rx-pairwise.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-pairwise.hpp @@ -67,7 +67,7 @@ struct pairwise dest.on_next(std::make_tuple(remembered.get(), v)); remembered.reset(v); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-reduce.hpp b/Rx/v2/src/rxcpp/operators/rx-reduce.hpp index 7fc9d08..e5dc819 100644 --- a/Rx/v2/src/rxcpp/operators/rx-reduce.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-reduce.hpp @@ -166,7 +166,7 @@ struct reduce : public operator_base<rxu::value_type_t<reduce_traits<T, Observab state->current = std::move(next); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed @@ -244,7 +244,7 @@ struct average { } return avg; } - throw rxcpp::empty_error("average() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("average() requires a stream with at least one value")); } }; @@ -264,7 +264,7 @@ struct sum { } T operator()(seed_type a) const { if (a.empty()) - throw rxcpp::empty_error("sum() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("sum() requires a stream with at least one value")); return *a; } }; @@ -283,7 +283,7 @@ struct max { } T operator()(seed_type a) { if (a.empty()) - throw rxcpp::empty_error("max() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("max() requires a stream with at least one value")); return *a; } }; @@ -302,7 +302,7 @@ struct min { } T operator()(seed_type a) { if (a.empty()) - throw rxcpp::empty_error("min() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("min() requires a stream with at least one value")); return *a; } }; @@ -320,7 +320,7 @@ struct first { } T operator()(seed_type a) { if (a.empty()) { - throw rxcpp::empty_error("first() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("first() requires a stream with at least one value")); } return *a; } @@ -339,7 +339,7 @@ struct last { } T operator()(seed_type a) { if (a.empty()) { - throw rxcpp::empty_error("last() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("last() requires a stream with at least one value")); } return *a; } diff --git a/Rx/v2/src/rxcpp/operators/rx-repeat.hpp b/Rx/v2/src/rxcpp/operators/rx-repeat.hpp index 97ba197..3b9ac89 100644 --- a/Rx/v2/src/rxcpp/operators/rx-repeat.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-repeat.hpp @@ -47,7 +47,7 @@ using repeat_invalid_t = typename repeat_invalid<AN...>::type; namespace repeat { struct event_handlers { template <typename State> - static inline void on_error(State& state, std::exception_ptr& e) { + static inline void on_error(State& state, rxu::error_ptr& e) { state->out.on_error(e); } diff --git a/Rx/v2/src/rxcpp/operators/rx-retry-repeat-common.hpp b/Rx/v2/src/rxcpp/operators/rx-retry-repeat-common.hpp index 373d9b3..30a71fe 100644 --- a/Rx/v2/src/rxcpp/operators/rx-retry-repeat-common.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-retry-repeat-common.hpp @@ -42,7 +42,7 @@ namespace rxcpp { state->out.on_next(t); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { EventHandlers::on_error(state, e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-retry.hpp b/Rx/v2/src/rxcpp/operators/rx-retry.hpp index 3cee7d3..63e5c27 100644 --- a/Rx/v2/src/rxcpp/operators/rx-retry.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-retry.hpp @@ -43,7 +43,7 @@ using retry_invalid_t = typename retry_invalid<AN...>::type; namespace retry { struct event_handlers { template <typename State> - static inline void on_error(State& state, std::exception_ptr& e) { + static inline void on_error(State& state, rxu::error_ptr& e) { state->update(); // Use specialized predicate for finite/infinte case if (state->completed_predicate()) { diff --git a/Rx/v2/src/rxcpp/operators/rx-sample_time.hpp b/Rx/v2/src/rxcpp/operators/rx-sample_time.hpp index fe1caa2..f50cbe4 100644 --- a/Rx/v2/src/rxcpp/operators/rx-sample_time.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-sample_time.hpp @@ -150,7 +150,7 @@ struct sample_with_time localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&) { localState->dest.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-scan.hpp b/Rx/v2/src/rxcpp/operators/rx-scan.hpp index b03be30..73bcd87 100644 --- a/Rx/v2/src/rxcpp/operators/rx-scan.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-scan.hpp @@ -90,7 +90,7 @@ struct scan : public operator_base<rxu::decay_t<Seed>> state->out.on_next(state->result); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp b/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp index 06253b4..3350e44 100644 --- a/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-sequence_equal.hpp @@ -161,7 +161,7 @@ struct sequence_equal : public operator_base<bool> check_equal(); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed @@ -189,7 +189,7 @@ struct sequence_equal : public operator_base<bool> check_equal(); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-skip.hpp b/Rx/v2/src/rxcpp/operators/rx-skip.hpp index c7f6c11..b77c4da 100644 --- a/Rx/v2/src/rxcpp/operators/rx-skip.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-skip.hpp @@ -109,7 +109,7 @@ struct skip : public operator_base<T> } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->mode_value = mode::errored; state->out.on_error(e); }, diff --git a/Rx/v2/src/rxcpp/operators/rx-skip_last.hpp b/Rx/v2/src/rxcpp/operators/rx-skip_last.hpp index 6641bd8..9594715 100644 --- a/Rx/v2/src/rxcpp/operators/rx-skip_last.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-skip_last.hpp @@ -103,7 +103,7 @@ struct skip_last : public operator_base<T> } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-skip_until.hpp b/Rx/v2/src/rxcpp/operators/rx-skip_until.hpp index 02a2424..4df6671 100644 --- a/Rx/v2/src/rxcpp/operators/rx-skip_until.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-skip_until.hpp @@ -139,7 +139,7 @@ struct skip_until : public operator_base<T> state->trigger_lifetime.unsubscribe(); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { if (state->mode_value != mode::skipping) { return; } @@ -174,7 +174,7 @@ struct skip_until : public operator_base<T> state->out.on_next(t); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { if (state->mode_value > mode::triggered) { return; } diff --git a/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp b/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp index fdd06b6..643d867 100644 --- a/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-skip_while.hpp @@ -75,7 +75,7 @@ struct skip_while dest.on_next(v); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp b/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp index b9bab52..8d3e57e 100644 --- a/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-switch_if_empty.hpp @@ -76,7 +76,7 @@ struct switch_if_empty is_empty = false; dest.on_next(std::move(v)); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(std::move(e)); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-switch_on_next.hpp b/Rx/v2/src/rxcpp/operators/rx-switch_on_next.hpp index b18963a..4572121 100644 --- a/Rx/v2/src/rxcpp/operators/rx-switch_on_next.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-switch_on_next.hpp @@ -155,7 +155,7 @@ struct switch_on_next state->out.on_next(std::move(ct)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, //on_completed @@ -171,7 +171,7 @@ struct switch_on_next selectedSource.subscribe(std::move(selectedSinkInner)); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-take.hpp b/Rx/v2/src/rxcpp/operators/rx-take.hpp index 054c136..1e4da4d 100644 --- a/Rx/v2/src/rxcpp/operators/rx-take.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-take.hpp @@ -112,7 +112,7 @@ struct take : public operator_base<T> } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->mode_value = mode::errored; state->out.on_error(e); }, diff --git a/Rx/v2/src/rxcpp/operators/rx-take_last.hpp b/Rx/v2/src/rxcpp/operators/rx-take_last.hpp index d59b355..12e28b6 100644 --- a/Rx/v2/src/rxcpp/operators/rx-take_last.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-take_last.hpp @@ -100,7 +100,7 @@ struct take_last : public operator_base<T> } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-take_until.hpp b/Rx/v2/src/rxcpp/operators/rx-take_until.hpp index 29aaf88..3fd9b71 100644 --- a/Rx/v2/src/rxcpp/operators/rx-take_until.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-take_until.hpp @@ -147,7 +147,7 @@ struct take_until : public operator_base<T> state->out.on_completed(); }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { if (state->mode_value != mode::taking) {return;} state->mode_value = mode::errored; state->out.on_error(e); @@ -179,7 +179,7 @@ struct take_until : public operator_base<T> } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { if (state->mode_value > mode::clear) {return;} state->mode_value = mode::errored; state->out.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-take_while.hpp b/Rx/v2/src/rxcpp/operators/rx-take_while.hpp index de1d57d..85630e7 100644 --- a/Rx/v2/src/rxcpp/operators/rx-take_while.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-take_while.hpp @@ -73,7 +73,7 @@ struct take_while dest.on_completed(); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-tap.hpp b/Rx/v2/src/rxcpp/operators/rx-tap.hpp index 51bfb2f..550163a 100644 --- a/Rx/v2/src/rxcpp/operators/rx-tap.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-tap.hpp @@ -92,7 +92,7 @@ struct tap out.on_next(v); dest.on_next(v); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { out.on_error(e); dest.on_error(e); } diff --git a/Rx/v2/src/rxcpp/operators/rx-time_interval.hpp b/Rx/v2/src/rxcpp/operators/rx-time_interval.hpp index 181c066..1a4c9a5 100644 --- a/Rx/v2/src/rxcpp/operators/rx-time_interval.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-time_interval.hpp @@ -84,7 +84,7 @@ struct time_interval dest.on_next(now - last); last = now; } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-timeout.hpp b/Rx/v2/src/rxcpp/operators/rx-timeout.hpp index 841df12..d100fa4 100644 --- a/Rx/v2/src/rxcpp/operators/rx-timeout.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-timeout.hpp @@ -147,7 +147,7 @@ struct timeout if(id != state->index) return; - state->dest.on_error(std::make_exception_ptr(rxcpp::timeout_error("timeout has occurred"))); + state->dest.on_error(rxu::make_error_ptr(rxcpp::timeout_error("timeout has occurred"))); }; auto selectedProduce = on_exception( @@ -178,7 +178,7 @@ struct timeout localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&) { localState->dest.on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-timestamp.hpp b/Rx/v2/src/rxcpp/operators/rx-timestamp.hpp index d1a11bf..923cf5d 100644 --- a/Rx/v2/src/rxcpp/operators/rx-timestamp.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-timestamp.hpp @@ -78,7 +78,7 @@ struct timestamp void on_next(source_value_type v) const { dest.on_next(std::make_pair(v, coord.now())); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { diff --git a/Rx/v2/src/rxcpp/operators/rx-window.hpp b/Rx/v2/src/rxcpp/operators/rx-window.hpp index e5d2c6f..e033a84 100644 --- a/Rx/v2/src/rxcpp/operators/rx-window.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-window.hpp @@ -103,7 +103,7 @@ struct window } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { for (auto s : subj) { s.get_subscriber().on_error(e); } diff --git a/Rx/v2/src/rxcpp/operators/rx-window_time.hpp b/Rx/v2/src/rxcpp/operators/rx-window_time.hpp index 17d4dd2..57f7572 100644 --- a/Rx/v2/src/rxcpp/operators/rx-window_time.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-window_time.hpp @@ -195,7 +195,7 @@ struct window_with_time localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&){ for (auto s : localState->subj) { diff --git a/Rx/v2/src/rxcpp/operators/rx-window_time_count.hpp b/Rx/v2/src/rxcpp/operators/rx-window_time_count.hpp index 39c64ad..9375737 100644 --- a/Rx/v2/src/rxcpp/operators/rx-window_time_count.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-window_time_count.hpp @@ -183,7 +183,7 @@ struct window_with_time_or_count localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&){ localState->subj.get_subscriber().on_error(e); diff --git a/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp b/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp index c17d4bc..b9f119a 100644 --- a/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp @@ -176,7 +176,7 @@ struct window_toggle innercs.unsubscribe(); }, // on_error - [localState](std::exception_ptr e) { + [localState](rxu::error_ptr e) { localState->dest.on_error(e); }, // on_completed @@ -186,7 +186,7 @@ struct window_toggle source.subscribe(std::move(selectedSink)); }, // on_error - [localState](std::exception_ptr e) { + [localState](rxu::error_ptr e) { localState->dest.on_error(e); }, // on_completed @@ -218,7 +218,7 @@ struct window_toggle localState->worker.schedule(selectedWork.get()); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { auto localState = state; auto work = [e, localState](const rxsc::schedulable&){ for (auto s : localState->subj) { 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 febba99..616e5d8 100644 --- a/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp @@ -173,7 +173,7 @@ struct with_latest_from : public operator_base<rxu::value_type_t<with_latest_fro } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/operators/rx-zip.hpp b/Rx/v2/src/rxcpp/operators/rx-zip.hpp index 90efe07..b8169fd 100644 --- a/Rx/v2/src/rxcpp/operators/rx-zip.hpp +++ b/Rx/v2/src/rxcpp/operators/rx-zip.hpp @@ -203,7 +203,7 @@ struct zip : public operator_base<rxu::value_type_t<zip_traits<Coordination, Sel } }, // on_error - [state](std::exception_ptr e) { + [state](rxu::error_ptr e) { state->out.on_error(e); }, // on_completed diff --git a/Rx/v2/src/rxcpp/rx-composite_exception.hpp b/Rx/v2/src/rxcpp/rx-composite_exception.hpp index 333f291..cddd03e 100644 --- a/Rx/v2/src/rxcpp/rx-composite_exception.hpp +++ b/Rx/v2/src/rxcpp/rx-composite_exception.hpp @@ -11,7 +11,7 @@ namespace rxcpp { struct composite_exception : std::exception { - typedef std::vector<std::exception_ptr> exception_values; + typedef std::vector<rxu::error_ptr> exception_values; virtual const char *what() const RXCPP_NOEXCEPT override { return "rxcpp composite exception"; @@ -21,7 +21,7 @@ struct composite_exception : std::exception { return exceptions.empty(); } - virtual composite_exception add(std::exception_ptr exception_ptr) { + virtual composite_exception add(rxu::error_ptr exception_ptr) { exceptions.push_back(exception_ptr); return *this; } diff --git a/Rx/v2/src/rxcpp/rx-coordination.hpp b/Rx/v2/src/rxcpp/rx-coordination.hpp index d2769e9..34e1223 100644 --- a/Rx/v2/src/rxcpp/rx-coordination.hpp +++ b/Rx/v2/src/rxcpp/rx-coordination.hpp @@ -227,7 +227,7 @@ class serialize_one_worker : public coordination_base std::unique_lock<std::mutex> guard(*lock); dest.on_next(v); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { std::unique_lock<std::mutex> guard(*lock); dest.on_error(e); } diff --git a/Rx/v2/src/rxcpp/rx-includes.hpp b/Rx/v2/src/rxcpp/rx-includes.hpp index 5104565..1eb47db 100644 --- a/Rx/v2/src/rxcpp/rx-includes.hpp +++ b/Rx/v2/src/rxcpp/rx-includes.hpp @@ -23,6 +23,12 @@ #define RXCPP_USE_RTTI 1 #endif +#if _HAS_EXCEPTIONS +#define RXCPP_USE_EXCEPTIONS 1 +#endif + +#define RXCPP_NORETURN __declspec(noreturn) + #elif defined(__clang__) #if __has_feature(cxx_rvalue_references) @@ -34,6 +40,15 @@ #if __has_feature(cxx_variadic_templates) #define RXCPP_USE_VARIADIC_TEMPLATES 1 #endif +#if __has_feature(cxx_exceptions) +#define RXCPP_USE_EXCEPTIONS 1 +#endif + +#if __has_feature(cxx_attributes) +#define RXCPP_NORETURN [[noreturn]] +#else +#define RXCPP_NORETURN __attribute__ ((noreturn)) +#endif #elif defined(__GNUG__) @@ -53,6 +68,12 @@ #define RXCPP_USE_RTTI 1 #endif +#if defined(__EXCEPTIONS) +#define RXCPP_USE_EXCEPTIONS 1 +#endif + +#define RXCPP_NORETURN __attribute__ ((noreturn)) + #endif // @@ -95,6 +116,11 @@ #define RXCPP_USE_RTTI RXCPP_FORCE_USE_RTTI #endif +#if defined(RXCPP_FORCE_USE_EXCEPTIONS) +#undef RXCPP_USE_EXCEPTIONS +#define RXCPP_USE_EXCEPTIONS RXCPP_FORCE_USE_EXCEPTIONS +#endif + #if defined(RXCPP_FORCE_USE_WINRT) #undef RXCPP_USE_WINRT #define RXCPP_USE_WINRT RXCPP_FORCE_USE_WINRT diff --git a/Rx/v2/src/rxcpp/rx-notification.hpp b/Rx/v2/src/rxcpp/rx-notification.hpp index c071e67..20e0c69 100644 --- a/Rx/v2/src/rxcpp/rx-notification.hpp +++ b/Rx/v2/src/rxcpp/rx-notification.hpp @@ -106,7 +106,7 @@ auto equals(const T& lhs, const T& rhs, int) template<class T> bool equals(const T&, const T&, ...) { - throw std::runtime_error("value does not support equality tests"); + rxu::throw_exception(std::runtime_error("value does not support equality tests")); return false; } @@ -146,26 +146,20 @@ private: }; struct on_error_notification : public base { - on_error_notification(std::exception_ptr ep) : ep(ep) { + on_error_notification(rxu::error_ptr ep) : ep(ep) { } on_error_notification(const on_error_notification& o) : ep(o.ep) {} on_error_notification(const on_error_notification&& o) : ep(std::move(o.ep)) {} on_error_notification& operator=(on_error_notification o) { ep = std::move(o.ep); return *this; } virtual void out(std::ostream& os) const { os << "on_error("; - try { - std::rethrow_exception(ep); - } catch (const std::exception& e) { - os << e.what(); - } catch (...) { - os << "<not derived from std::exception>"; - } + os << rxu::what(ep); os << ")"; } virtual bool equals(const typename base::type& other) const { bool result = false; // not trying to compare exceptions - other->accept(make_subscriber<T>(make_observer_dynamic<T>([](T){}, [&result](std::exception_ptr){ + other->accept(make_subscriber<T>(make_observer_dynamic<T>([](T){}, [&result](rxu::error_ptr){ result = true; }))); return result; @@ -173,7 +167,7 @@ private: virtual void accept(const typename base::observer_type& o) const { o.on_error(ep); } - const std::exception_ptr ep; + const rxu::error_ptr ep; }; struct on_completed_notification : public base { @@ -199,20 +193,14 @@ private: template<typename Exception> static type make_on_error(exception_tag&&, Exception&& e) { - std::exception_ptr ep; - try { - throw std::forward<Exception>(e); - } - catch (...) { - ep = std::current_exception(); - } + rxu::error_ptr ep = rxu::make_error_ptr(std::forward<Exception>(e)); return std::make_shared<on_error_notification>(ep); } struct exception_ptr_tag {}; static - type make_on_error(exception_ptr_tag&&, std::exception_ptr ep) { + type make_on_error(exception_ptr_tag&&, rxu::error_ptr ep) { return std::make_shared<on_error_notification>(ep); } @@ -229,7 +217,7 @@ public: template<typename Exception> static type on_error(Exception&& e) { return make_on_error(typename std::conditional< - std::is_same<rxu::decay_t<Exception>, std::exception_ptr>::value, + std::is_same<rxu::decay_t<Exception>, rxu::error_ptr>::value, exception_ptr_tag, exception_tag>::type(), std::forward<Exception>(e)); } @@ -280,8 +268,6 @@ std::ostream& operator<< (std::ostream& out, const recorded<T>& r) { } namespace rxn=notifications; -} - inline std::ostream& operator<< (std::ostream& out, const std::vector<rxcpp::notifications::subscription>& vs) { return rxcpp::notifications::detail::ostreamvector(out, vs); } @@ -290,4 +276,6 @@ inline std::ostream& operator<< (std::ostream& out, const std::vector<rxcpp::not return rxcpp::notifications::detail::ostreamvector(out, vr); } +} + #endif diff --git a/Rx/v2/src/rxcpp/rx-observable.hpp b/Rx/v2/src/rxcpp/rx-observable.hpp index 037f375..97bcabd 100644 --- a/Rx/v2/src/rxcpp/rx-observable.hpp +++ b/Rx/v2/src/rxcpp/rx-observable.hpp @@ -174,7 +174,7 @@ class blocking_observable std::mutex lock; std::condition_variable wake; bool disposed = false; - std::exception_ptr error; + rxu::error_ptr error; auto dest = make_subscriber<T>(std::forward<ArgN>(an)...); @@ -182,7 +182,7 @@ class blocking_observable auto scbr = make_subscriber<T>( dest, [&](T t){dest.on_next(t);}, - [&](std::exception_ptr e){ + [&](rxu::error_ptr e){ if (do_rethrow) { error = e; } else { @@ -208,7 +208,7 @@ class blocking_observable return disposed; }); - if (error) {std::rethrow_exception(error);} + if (error) {rxu::rethrow_exception(error);} } public: @@ -288,7 +288,7 @@ public: cs, [&](T v){result.reset(v); cs.unsubscribe();}); if (result.empty()) - throw rxcpp::empty_error("first() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("first() requires a stream with at least one value")); return result.get(); static_assert(sizeof...(AN) == 0, "first() was passed too many arguments."); } @@ -314,7 +314,7 @@ public: subscribe_with_rethrow( [&](T v){result.reset(v);}); if (result.empty()) - throw rxcpp::empty_error("last() requires a stream with at least one value"); + rxu::throw_exception(rxcpp::empty_error("last() requires a stream with at least one value")); return result.get(); static_assert(sizeof...(AN) == 0, "last() was passed too many arguments."); } @@ -431,14 +431,13 @@ struct safe_subscriber safe_subscriber(SourceOperator& so, Subscriber& o) : so(std::addressof(so)), o(std::addressof(o)) {} void subscribe() { - try { + RXCPP_TRY { so->on_subscribe(*o); - } - catch(...) { + } RXCPP_CATCH(...) { if (!o->is_subscribed()) { - throw; + rxu::rethrow_current_exception(); } - o->on_error(std::current_exception()); + o->on_error(rxu::make_error_ptr(rxu::current_exception())); o->unsubscribe(); } } diff --git a/Rx/v2/src/rxcpp/rx-observer.hpp b/Rx/v2/src/rxcpp/rx-observer.hpp index 62aed3c..92321f1 100644 --- a/Rx/v2/src/rxcpp/rx-observer.hpp +++ b/Rx/v2/src/rxcpp/rx-observer.hpp @@ -25,14 +25,14 @@ struct OnNextEmpty }; struct OnErrorEmpty { - void operator()(std::exception_ptr) const { + void operator()(rxu::error_ptr) const { // error implicitly ignored, abort std::terminate(); } }; struct OnErrorIgnore { - void operator()(std::exception_ptr) const { + void operator()(rxu::error_ptr) const { } }; struct OnCompletedEmpty @@ -76,7 +76,7 @@ struct OnErrorForward OnErrorForward() : onerror() {} explicit OnErrorForward(onerror_t oe) : onerror(std::move(oe)) {} onerror_t onerror; - void operator()(state_t& s, std::exception_ptr ep) const { + void operator()(state_t& s, rxu::error_ptr ep) const { onerror(s, ep); } }; @@ -85,7 +85,7 @@ struct OnErrorForward<State, void> { using state_t = rxu::decay_t<State>; OnErrorForward() {} - void operator()(state_t& s, std::exception_ptr ep) const { + void operator()(state_t& s, rxu::error_ptr ep) const { s.on_error(ep); } }; @@ -129,7 +129,7 @@ struct is_on_error { struct not_void {}; template<class CF> - static auto check(int) -> decltype((*(CF*)nullptr)(*(std::exception_ptr*)nullptr)); + static auto check(int) -> decltype((*(CF*)nullptr)(*(rxu::error_ptr*)nullptr)); template<class CF> static not_void check(...); @@ -141,7 +141,7 @@ struct is_on_error_for { struct not_void {}; template<class CF> - static auto check(int) -> decltype((*(CF*)nullptr)(*(State*)nullptr, *(std::exception_ptr*)nullptr)); + static auto check(int) -> decltype((*(CF*)nullptr)(*(State*)nullptr, *(rxu::error_ptr*)nullptr)); template<class CF> static not_void check(...); @@ -169,7 +169,7 @@ struct is_on_completed \tparam T - the type of value in the stream \tparam State - the type of the stored state \tparam OnNext - the type of a function that matches `void(State&, T)`. Called 0 or more times. If `void` State::on_next will be called. - \tparam OnError - the type of a function that matches `void(State&, std::exception_ptr)`. Called 0 or 1 times, no further calls will be made. If `void` State::on_error will be called. + \tparam OnError - the type of a function that matches `void(State&, rxu::error_ptr)`. Called 0 or 1 times, no further calls will be made. If `void` State::on_error will be called. \tparam OnCompleted - the type of a function that matches `void(State&)`. Called 0 or 1 times, no further calls will be made. If `void` State::on_completed will be called. \ingroup group-core @@ -244,7 +244,7 @@ public: void on_next(T&& t) const { onnext(state, std::move(t)); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { onerror(state, e); } void on_completed() const { @@ -260,7 +260,7 @@ public: \tparam T - the type of value in the stream \tparam OnNext - the type of a function that matches `void(T)`. Called 0 or more times. If `void` OnNextEmpty<T> is used. - \tparam OnError - the type of a function that matches `void(std::exception_ptr)`. Called 0 or 1 times, no further calls will be made. If `void` OnErrorEmpty is used. + \tparam OnError - the type of a function that matches `void(rxu::error_ptr)`. Called 0 or 1 times, no further calls will be made. If `void` OnErrorEmpty is used. \tparam OnCompleted - the type of a function that matches `void()`. Called 0 or 1 times, no further calls will be made. If `void` OnCompletedEmpty is used. \ingroup group-core @@ -291,7 +291,7 @@ private: public: static_assert(detail::is_on_next_of<T, on_next_t>::value, "Function supplied for on_next must be a function with the signature void(T);"); - static_assert(detail::is_on_error<on_error_t>::value, "Function supplied for on_error must be a function with the signature void(std::exception_ptr);"); + static_assert(detail::is_on_error<on_error_t>::value, "Function supplied for on_error must be a function with the signature void(rxu::error_ptr);"); static_assert(detail::is_on_completed<on_completed_t>::value, "Function supplied for on_completed must be a function with the signature void();"); observer() @@ -332,7 +332,7 @@ public: void on_next(T&& t) const { onnext(std::move(t)); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { onerror(e); } void on_completed() const { @@ -352,7 +352,7 @@ struct virtual_observer : public std::enable_shared_from_this<virtual_observer<T virtual ~virtual_observer() {} virtual void on_next(T&) const {}; virtual void on_next(T&&) const {}; - virtual void on_error(std::exception_ptr) const {}; + virtual void on_error(rxu::error_ptr) const {}; virtual void on_completed() const {}; }; @@ -371,7 +371,7 @@ struct specific_observer : public virtual_observer<T> virtual void on_next(T&& t) const { destination.on_next(std::move(t)); } - virtual void on_error(std::exception_ptr e) const { + virtual void on_error(rxu::error_ptr e) const { destination.on_error(e); } virtual void on_completed() const { @@ -439,7 +439,7 @@ public: destination->on_next(std::forward<V>(v)); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { if (destination) { destination->on_error(e); } @@ -640,10 +640,10 @@ template<class F, class OnError> auto on_exception(const F& f, const OnError& c) -> typename std::enable_if<detail::is_on_error<OnError>::value, typename detail::maybe_from_result<F>::type>::type { typename detail::maybe_from_result<F>::type r; - try { + RXCPP_TRY { r.reset(f()); - } catch (...) { - c(std::current_exception()); + } RXCPP_CATCH(...) { + c(rxu::current_exception()); } return r; } @@ -652,10 +652,10 @@ template<class F, class Subscriber> auto on_exception(const F& f, const Subscriber& s) -> typename std::enable_if<is_subscriber<Subscriber>::value, typename detail::maybe_from_result<F>::type>::type { typename detail::maybe_from_result<F>::type r; - try { + RXCPP_TRY { r.reset(f()); - } catch (...) { - s.on_error(std::current_exception()); + } RXCPP_CATCH(...) { + s.on_error(rxu::current_exception()); } return r; } diff --git a/Rx/v2/src/rxcpp/rx-subscriber.hpp b/Rx/v2/src/rxcpp/rx-subscriber.hpp index abdb7b6..3d6c515 100644 --- a/Rx/v2/src/rxcpp/rx-subscriber.hpp +++ b/Rx/v2/src/rxcpp/rx-subscriber.hpp @@ -50,11 +50,11 @@ class subscriber : public subscriber_base<T> template<class U> void operator()(U u) { trace_activity().on_next_enter(*that, u); - try { + RXCPP_TRY { that->destination.on_next(std::move(u)); do_unsubscribe = false; - } catch(...) { - auto ex = std::current_exception(); + } RXCPP_CATCH(...) { + auto ex = rxu::current_exception(); trace_activity().on_error_enter(*that, ex); that->destination.on_error(std::move(ex)); trace_activity().on_error_return(*that); @@ -75,7 +75,7 @@ class subscriber : public subscriber_base<T> : that(that) { } - inline void operator()(std::exception_ptr ex) { + inline void operator()(rxu::error_ptr ex) { trace_activity().on_error_enter(*that, ex); that->destination.on_error(std::move(ex)); } @@ -180,7 +180,7 @@ public: nextdetacher protect(this); protect(std::forward<V>(v)); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { if (!is_subscribed()) { return; } diff --git a/Rx/v2/src/rxcpp/rx-trace.hpp b/Rx/v2/src/rxcpp/rx-trace.hpp index a148953..bf0abaf 100644 --- a/Rx/v2/src/rxcpp/rx-trace.hpp +++ b/Rx/v2/src/rxcpp/rx-trace.hpp @@ -93,8 +93,8 @@ struct trace_noop template<class Subscriber> inline void on_next_return(const Subscriber&) {} - template<class Subscriber> - inline void on_error_enter(const Subscriber&, const std::exception_ptr&) {} + template<class Subscriber, class ErrorPtr> + inline void on_error_enter(const Subscriber&, const ErrorPtr&) {} template<class Subscriber> inline void on_error_return(const Subscriber&) {} diff --git a/Rx/v2/src/rxcpp/rx-util.hpp b/Rx/v2/src/rxcpp/rx-util.hpp index d4d5536..e5867e5 100644 --- a/Rx/v2/src/rxcpp/rx-util.hpp +++ b/Rx/v2/src/rxcpp/rx-util.hpp @@ -28,6 +28,18 @@ #define RXCPP_MAKE_IDENTIFIER(Prefix) RXCPP_CONCAT_EVALUATE(Prefix, __LINE__) +// Provide replacements for try/catch keywords, using which is a compilation error +// when exceptions are disabled with -fno-exceptions. +#if RXCPP_USE_EXCEPTIONS +#define RXCPP_TRY try +#define RXCPP_CATCH(...) catch(__VA_ARGS__) +// See also rxu::throw_exception for 'throw' keyword replacement. +#else +#define RXCPP_TRY if ((true)) +#define RXCPP_CATCH(...) if ((false)) +// See also rxu::throw_exception, which will std::terminate without exceptions. +#endif + namespace rxcpp { namespace util { @@ -530,11 +542,16 @@ auto print_followed_by(OStream& os, DelimitValue dv) } inline std::string what(std::exception_ptr ep) { +#if RXCPP_USE_EXCEPTIONS try {std::rethrow_exception(ep);} catch (const std::exception& ex) { return ex.what(); + } catch (...) { + return std::string("<not derived from std::exception>"); } - return std::string(); +#endif + (void)ep; + return std::string("<exceptions are disabled>"); } namespace detail { @@ -699,9 +716,9 @@ public: { if (!!function) { - try { + RXCPP_TRY { (*function)(); - } catch (...) { + } RXCPP_CATCH(...) { std::terminate(); } } @@ -811,6 +828,129 @@ template <class T> struct negation : detail::not_value<T> {}; } + +#if !RXCPP_USE_EXCEPTIONS +namespace util { + +namespace detail { + +struct error_base { + virtual const char* what() = 0; + virtual ~error_base() {} +}; + +// Use the "Type Erasure" idiom to wrap an std::exception-like +// value into an error pointer. +// +// Supported types: +// exception, bad_exception, bad_alloc. +template <class E> +struct error_specific : public error_base { + error_specific(const E& e) : data(e) {} + error_specific(E&& e) : data(std::move(e)) {} + + virtual ~error_specific() {} + + virtual const char* what() { + return data.what(); + } + + E data; +}; + +} + +} +#endif + +namespace util { + +#if RXCPP_USE_EXCEPTIONS +using error_ptr = std::exception_ptr; +#else +// Note: std::exception_ptr cannot be used directly when exceptions are disabled. +// Any attempt to 'throw' or to call into any of the std functions accepting +// an std::exception_ptr will either fail to compile or result in an abort at runtime. +using error_ptr = std::shared_ptr<util::detail::error_base>; + +inline std::string what(error_ptr ep) { + return std::string(ep->what()); +} +#endif + +// TODO: Do we really need an identity make? +// (It was causing some compilation errors deep inside templates). +inline error_ptr make_error_ptr(error_ptr e) { + return e; +} + +// Replace std::make_exception_ptr (which would immediately terminate +// when exceptions are disabled). +template <class E> +error_ptr make_error_ptr(E&& e) { +#if RXCPP_USE_EXCEPTIONS + return std::make_exception_ptr(std::forward<E>(e)); +#else + using e_type = rxcpp::util::decay_t<E>; + using pointed_to_type = rxcpp::util::detail::error_specific<e_type>; + auto sp = std::make_shared<pointed_to_type>(std::forward<E>(e)); + return std::static_pointer_cast<rxcpp::util::detail::error_base>(sp); +#endif +} + +// Replace std::rethrow_exception to be compatible with our error_ptr typedef. +RXCPP_NORETURN inline void rethrow_exception(error_ptr e) { +#if RXCPP_USE_EXCEPTIONS + std::rethrow_exception(e); +#else + // error_ptr != std::exception_ptr so we can't use std::rethrow_exception + // + // However even if we could, calling std::rethrow_exception just terminates if exceptions are disabled. + // + // Therefore this function should only be called when we are completely giving up and have no idea + // how to handle the error. + (void)e; + std::terminate(); +#endif +} + +// A replacement for the "throw" keyword which is illegal when +// exceptions are disabled with -fno-exceptions. +template <typename E> +RXCPP_NORETURN inline void throw_exception(E&& e) { +#if RXCPP_USE_EXCEPTIONS + throw std::forward<E>(e); +#else + // "throw" keyword is unsupported when exceptions are disabled. + // Immediately terminate instead. + (void)e; + std::terminate(); +#endif +} + +// TODO: Do we really need this? rxu::rethrow_exception(rxu::current_exception()) +// would have the same semantics in either case. +RXCPP_NORETURN inline void rethrow_current_exception() { +#if RXCPP_USE_EXCEPTIONS + std::rethrow_exception(std::current_exception()); +#else + std::terminate(); +#endif +} + +// If called during exception handling, return the currently caught exception. +// Otherwise return null. +inline error_ptr current_exception() { +#if RXCPP_USE_EXCEPTIONS + return std::current_exception(); +#else + // When exceptions are disabled, we can never be inside of a catch block. + // Return null similar to std::current_exception returning null outside of catch. + return nullptr; +#endif +} + +} namespace rxu=util; diff --git a/Rx/v2/src/rxcpp/schedulers/rx-test.hpp b/Rx/v2/src/rxcpp/schedulers/rx-test.hpp index 3f73e52..aaa073d 100644 --- a/Rx/v2/src/rxcpp/schedulers/rx-test.hpp +++ b/Rx/v2/src/rxcpp/schedulers/rx-test.hpp @@ -200,7 +200,7 @@ subscriber<T, rxt::testable_observer<T>> test_type::test_type_worker::make_subsc recorded_type(ts->sc->clock(), notification_type::on_next(value))); }, // on_error - [ts](std::exception_ptr e) + [ts](rxu::error_ptr e) { ts->m.push_back( recorded_type(ts->sc->clock(), notification_type::on_error(e))); diff --git a/Rx/v2/src/rxcpp/sources/rx-error.hpp b/Rx/v2/src/rxcpp/sources/rx-error.hpp index 461c081..f245d02 100644 --- a/Rx/v2/src/rxcpp/sources/rx-error.hpp +++ b/Rx/v2/src/rxcpp/sources/rx-error.hpp @@ -46,17 +46,17 @@ struct error : public source_base<T> struct error_initial_type { - error_initial_type(std::exception_ptr e, coordination_type cn) + error_initial_type(rxu::error_ptr e, coordination_type cn) : exception(e) , coordination(std::move(cn)) { } - std::exception_ptr exception; + rxu::error_ptr exception; coordination_type coordination; }; error_initial_type initial; - error(std::exception_ptr e, coordination_type cn) + error(rxu::error_ptr e, coordination_type cn) : initial(e, std::move(cn)) { } @@ -93,7 +93,7 @@ struct throw_ptr_tag{}; struct throw_instance_tag{}; template <class T, class Coordination> -auto make_error(throw_ptr_tag&&, std::exception_ptr exception, Coordination cn) +auto make_error(throw_ptr_tag&&, rxu::error_ptr exception, Coordination cn) -> observable<T, error<T, Coordination>> { return observable<T, error<T, Coordination>>(error<T, Coordination>(std::move(exception), std::move(cn))); } @@ -101,26 +101,29 @@ auto make_error(throw_ptr_tag&&, std::exception_ptr exception, Coordination cn) template <class T, class E, class Coordination> auto make_error(throw_instance_tag&&, E e, Coordination cn) -> observable<T, error<T, Coordination>> { - std::exception_ptr exception; - try {throw e;} catch(...) {exception = std::current_exception();} - return observable<T, error<T, Coordination>>(error<T, Coordination>(std::move(exception), std::move(cn))); + rxu::error_ptr ep = rxu::make_error_ptr(e); + return observable<T, error<T, Coordination>>(error<T, Coordination>(std::move(ep), std::move(cn))); +} + } } +namespace sources { + /*! @copydoc rx-error.hpp */ template<class T, class E> auto error(E e) - -> decltype(detail::make_error<T>(typename std::conditional<std::is_same<std::exception_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), identity_immediate())) { - return detail::make_error<T>(typename std::conditional<std::is_same<std::exception_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), identity_immediate()); + -> decltype(detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), identity_immediate())) { + return detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), identity_immediate()); } /*! @copydoc rx-error.hpp */ template<class T, class E, class Coordination> auto error(E e, Coordination cn) - -> decltype(detail::make_error<T>(typename std::conditional<std::is_same<std::exception_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), std::move(cn))) { - return detail::make_error<T>(typename std::conditional<std::is_same<std::exception_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), std::move(cn)); + -> decltype(detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), std::move(cn))) { + return detail::make_error<T>(typename std::conditional<std::is_same<rxu::error_ptr, rxu::decay_t<E>>::value, detail::throw_ptr_tag, detail::throw_instance_tag>::type(), std::move(e), std::move(cn)); } } diff --git a/Rx/v2/src/rxcpp/subjects/rx-subject.hpp b/Rx/v2/src/rxcpp/subjects/rx-subject.hpp index a77c0c4..4ce96b4 100644 --- a/Rx/v2/src/rxcpp/subjects/rx-subject.hpp +++ b/Rx/v2/src/rxcpp/subjects/rx-subject.hpp @@ -40,7 +40,7 @@ class multicast_observer } std::mutex lock; typename mode::type current; - std::exception_ptr error; + rxu::error_ptr error; composite_subscription lifetime; }; @@ -191,7 +191,7 @@ public: } } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { std::unique_lock<std::mutex> guard(b->state->lock); if (b->state->current == mode::Casting) { b->state->error = e; diff --git a/Rx/v2/src/rxcpp/subjects/rx-synchronize.hpp b/Rx/v2/src/rxcpp/subjects/rx-synchronize.hpp index 161b422..858eef3 100644 --- a/Rx/v2/src/rxcpp/subjects/rx-synchronize.hpp +++ b/Rx/v2/src/rxcpp/subjects/rx-synchronize.hpp @@ -56,7 +56,7 @@ class synchronize_observer : public detail::multicast_observer<T> auto keepAlive = this->shared_from_this(); auto drain_queue = [keepAlive, this](const rxsc::schedulable& self){ - try { + RXCPP_TRY { std::unique_lock<std::mutex> guard(lock); if (!destination.is_subscribed()) { current = mode::Disposed; @@ -74,8 +74,8 @@ class synchronize_observer : public detail::multicast_observer<T> guard.unlock(); notification->accept(destination); self(); - } catch(...) { - destination.on_error(std::current_exception()); + } RXCPP_CATCH(...) { + destination.on_error(rxu::current_exception()); std::unique_lock<std::mutex> guard(lock); current = mode::Empty; } @@ -110,7 +110,7 @@ class synchronize_observer : public detail::multicast_observer<T> } wake.notify_one(); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { if (lifetime.is_subscribed()) { std::unique_lock<std::mutex> guard(lock); fill_queue.push_back(notification_type::on_error(e)); @@ -150,7 +150,7 @@ public: void on_next(V v) const { state->on_next(std::move(v)); } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { state->on_error(e); } void on_completed() const { diff --git a/Rx/v2/test/CMakeLists.txt b/Rx/v2/test/CMakeLists.txt index dcb998f..c2d1530 100644 --- a/Rx/v2/test/CMakeLists.txt +++ b/Rx/v2/test/CMakeLists.txt @@ -88,6 +88,15 @@ set(TEST_SOURCES ${TEST_DIR}/operators/zip.cpp ) +set(TEST_COMPILE_DEFINITIONS "") +set(TEST_COMMAND_ARGUMENTS "") + +if (NOT RX_USE_EXCEPTIONS) + MESSAGE( STATUS "no exceptions" ) + list(APPEND TEST_COMPILE_DEFINITIONS CATCH_CONFIG_DISABLE_EXCEPTIONS) + list(APPEND TEST_COMMAND_ARGUMENTS -e) +endif() + add_executable(rxcppv2_test ${TEST_DIR}/test.cpp ${TEST_SOURCES}) add_executable(rxcpp::tests ALIAS rxcppv2_test) @@ -98,6 +107,7 @@ set_target_properties( ) target_compile_options(rxcppv2_test PUBLIC ${RX_COMPILE_OPTIONS}) target_compile_features(rxcppv2_test PUBLIC ${RX_COMPILE_FEATURES}) +target_compile_definitions(rxcppv2_test PUBLIC ${TEST_COMPILE_DEFINITIONS}) target_include_directories(rxcppv2_test PUBLIC ${RX_SRC_DIR} ${RX_CATCH_DIR} ) @@ -110,7 +120,7 @@ foreach(ONE_TEST_SOURCE ${TEST_SOURCES}) set(ONE_TEST_FULL_NAME "rxcpp_test_${ONE_TEST_NAME}") add_executable( ${ONE_TEST_FULL_NAME} ${ONE_TEST_SOURCE} ) add_executable( rxcpp::${ONE_TEST_NAME} ALIAS ${ONE_TEST_FULL_NAME}) - target_compile_definitions(${ONE_TEST_FULL_NAME} PUBLIC "CATCH_CONFIG_MAIN") + target_compile_definitions(${ONE_TEST_FULL_NAME} PUBLIC "CATCH_CONFIG_MAIN" ${TEST_COMPILE_DEFINITIONS}) target_compile_options(${ONE_TEST_FULL_NAME} PUBLIC ${RX_COMPILE_OPTIONS}) target_compile_features(${ONE_TEST_FULL_NAME} PUBLIC ${RX_COMPILE_FEATURES}) target_include_directories(${ONE_TEST_FULL_NAME} @@ -118,7 +128,7 @@ foreach(ONE_TEST_SOURCE ${TEST_SOURCES}) ) target_link_libraries(${ONE_TEST_FULL_NAME} ${CMAKE_THREAD_LIBS_INIT}) - add_test(NAME ${ONE_TEST_NAME} COMMAND ${ONE_TEST_FULL_NAME}) + add_test(NAME ${ONE_TEST_NAME} COMMAND ${ONE_TEST_FULL_NAME} ${TEST_COMMAND_ARGUMENTS}) endforeach(ONE_TEST_SOURCE ${TEST_SOURCES}) diff --git a/Rx/v2/test/operators/buffer.cpp b/Rx/v2/test/operators/buffer.cpp index 51aba17..e1b980c 100644 --- a/Rx/v2/test/operators/buffer.cpp +++ b/Rx/v2/test/operators/buffer.cpp @@ -455,7 +455,7 @@ SCENARIO("buffer count error 2", "[buffer][operators]"){ } } -SCENARIO("buffer with time on intervals", "[buffer_with_time][operators][long][hide]"){ +SCENARIO("buffer with time on intervals", "[buffer_with_time][operators][long][!hide]"){ GIVEN("7 intervals of 2 seconds"){ WHEN("the period is 2sec and the initial is 5sec"){ // time: |-----------------| @@ -489,7 +489,7 @@ SCENARIO("buffer with time on intervals", "[buffer_with_time][operators][long][h }); printf("\n"); }, - [](std::exception_ptr){ + [](rxu::error_ptr){ printf("on_error\n"); }, [](){ @@ -500,7 +500,7 @@ SCENARIO("buffer with time on intervals", "[buffer_with_time][operators][long][h } } -SCENARIO("buffer with time on intervals, implicit coordination", "[buffer_with_time][operators][long][hide]"){ +SCENARIO("buffer with time on intervals, implicit coordination", "[buffer_with_time][operators][long][!hide]"){ GIVEN("7 intervals of 2 seconds"){ WHEN("the period is 2sec and the initial is 5sec"){ // time: |-----------------| @@ -532,7 +532,7 @@ SCENARIO("buffer with time on intervals, implicit coordination", "[buffer_with_t }); printf("\n"); }, - [](std::exception_ptr){ + [](rxu::error_ptr){ printf("on_error\n"); }, [](){ @@ -543,7 +543,7 @@ SCENARIO("buffer with time on intervals, implicit coordination", "[buffer_with_t } } -SCENARIO("buffer with time on overlapping intervals", "[buffer_with_time][operators][long][hide]"){ +SCENARIO("buffer with time on overlapping intervals", "[buffer_with_time][operators][long][!hide]"){ GIVEN("5 intervals of 2 seconds"){ WHEN("the period is 2sec and the initial is 5sec"){ // time: |-------------| @@ -576,7 +576,7 @@ SCENARIO("buffer with time on overlapping intervals", "[buffer_with_time][operat }); printf("\n"); }, - [](std::exception_ptr){ + [](rxu::error_ptr){ printf("on_error\n"); }, [](){ @@ -587,7 +587,7 @@ SCENARIO("buffer with time on overlapping intervals", "[buffer_with_time][operat } } -SCENARIO("buffer with time on overlapping intervals, implicit coordination", "[buffer_with_time][operators][long][hide]"){ +SCENARIO("buffer with time on overlapping intervals, implicit coordination", "[buffer_with_time][operators][long][!hide]"){ GIVEN("5 intervals of 2 seconds"){ WHEN("the period is 2sec and the initial is 5sec"){ // time: |-------------| @@ -620,7 +620,7 @@ SCENARIO("buffer with time on overlapping intervals, implicit coordination", "[b }); printf("\n"); }, - [](std::exception_ptr){ + [](rxu::error_ptr){ printf("on_error\n"); }, [](){ @@ -631,7 +631,7 @@ SCENARIO("buffer with time on overlapping intervals, implicit coordination", "[b } } -SCENARIO("buffer with time on intervals, error", "[buffer_with_time][operators][long][hide]"){ +SCENARIO("buffer with time on intervals, error", "[buffer_with_time][operators][long][!hide]"){ GIVEN("5 intervals of 2 seconds"){ WHEN("the period is 2sec and the initial is 5sec"){ // time: |-------------| @@ -667,7 +667,7 @@ SCENARIO("buffer with time on intervals, error", "[buffer_with_time][operators][ }); printf("\n"); }, - [](std::exception_ptr){ + [](rxu::error_ptr){ printf("on_error\n"); }, [](){ diff --git a/Rx/v2/test/operators/combine_latest.cpp b/Rx/v2/test/operators/combine_latest.cpp index ec47823..198fb2f 100644 --- a/Rx/v2/test/operators/combine_latest.cpp +++ b/Rx/v2/test/operators/combine_latest.cpp @@ -1465,7 +1465,7 @@ SCENARIO("combine_latest error after completed right", "[combine_latest][join][o } } -SCENARIO("combine_latest selector throws", "[combine_latest][join][operators]"){ +SCENARIO("combine_latest selector throws", "[combine_latest][join][operators][!throws]"){ GIVEN("2 hot observables of ints."){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -1491,8 +1491,25 @@ SCENARIO("combine_latest selector throws", "[combine_latest][join][operators]"){ [&]() { return o1 .combine_latest( + // Note for trying to handle this test case when exceptions are disabled + // with RXCPP_USE_EXCEPTIONS == 0: + // + // It seems that this test is in particular testing that the + // combine_latest selector (aggregate function) thrown exceptions + // are being translated into an on_error. + // + // Since there appears to be no way to give combine_latest + // an Observable that would call on_error directly (as opposed + // to a regular function that's converted into an observable), + // this test is meaningless when exceptions are disabled + // since any selectors with 'throw' will not even compile. + // + // Attempting to change this to e.g. + // o1.combineLatest(o2).map ... unconditional onError + // would defeat the purpose of the test since its the combineLatest + // implementation that's supposed to be doing the error forwarding. [&ex](int, int) -> int { - throw ex; + rxu::throw_exception(ex); }, o2 ) @@ -1528,7 +1545,7 @@ SCENARIO("combine_latest selector throws", "[combine_latest][join][operators]"){ } } -SCENARIO("combine_latest selector throws N", "[combine_latest][join][operators]"){ +SCENARIO("combine_latest selector throws N", "[combine_latest][join][operators][!throws]"){ GIVEN("N hot observables of ints."){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -1555,7 +1572,7 @@ SCENARIO("combine_latest selector throws N", "[combine_latest][join][operators]" return e[0] .combine_latest( [&ex](int, int, int, int) -> int { - throw ex; + rxu::throw_exception(ex); }, e[1], e[2], e[3] ) diff --git a/Rx/v2/test/operators/concat.cpp b/Rx/v2/test/operators/concat.cpp index 86f4a7e..88dcac7 100644 --- a/Rx/v2/test/operators/concat.cpp +++ b/Rx/v2/test/operators/concat.cpp @@ -5,7 +5,7 @@ const int static_onnextcalls = 1000000; -SCENARIO("synchronize concat ranges", "[hide][range][synchronize][concat][perf]"){ +SCENARIO("synchronize concat ranges", "[!hide][range][synchronize][concat][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("some ranges"){ WHEN("generating ints"){ @@ -33,7 +33,7 @@ SCENARIO("synchronize concat ranges", "[hide][range][synchronize][concat][perf]" } } -SCENARIO("observe_on concat ranges", "[hide][range][observe_on][concat][perf]"){ +SCENARIO("observe_on concat ranges", "[!hide][range][observe_on][concat][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("some ranges"){ WHEN("generating ints"){ @@ -61,7 +61,7 @@ SCENARIO("observe_on concat ranges", "[hide][range][observe_on][concat][perf]"){ } } -SCENARIO("serialize concat ranges", "[hide][range][serialize][concat][perf]"){ +SCENARIO("serialize concat ranges", "[!hide][range][serialize][concat][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("some ranges"){ WHEN("generating ints"){ diff --git a/Rx/v2/test/operators/concat_map.cpp b/Rx/v2/test/operators/concat_map.cpp index e6551d6..cfd6f4f 100644 --- a/Rx/v2/test/operators/concat_map.cpp +++ b/Rx/v2/test/operators/concat_map.cpp @@ -8,7 +8,7 @@ static const int static_tripletCount = 100; -SCENARIO("concat_transform pythagorian ranges", "[hide][range][concat_transform][pythagorian][perf]"){ +SCENARIO("concat_transform pythagorian ranges", "[!hide][range][concat_transform][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ @@ -43,7 +43,7 @@ SCENARIO("concat_transform pythagorian ranges", "[hide][range][concat_transform] .take(tripletCount) .subscribe( rxu::apply_to([&ct](int /*x*/,int /*y*/,int /*z*/){++ct;}), - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); auto finish = clock::now(); auto msElapsed = duration_cast<milliseconds>(finish.time_since_epoch()) - duration_cast<milliseconds>(start.time_since_epoch()); @@ -53,7 +53,7 @@ SCENARIO("concat_transform pythagorian ranges", "[hide][range][concat_transform] } } -SCENARIO("synchronize concat_transform pythagorian ranges", "[hide][range][concat_transform][synchronize][pythagorian][perf]"){ +SCENARIO("synchronize concat_transform pythagorian ranges", "[!hide][range][concat_transform][synchronize][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ @@ -101,7 +101,7 @@ SCENARIO("synchronize concat_transform pythagorian ranges", "[hide][range][conca } } -SCENARIO("observe_on concat_transform pythagorian ranges", "[hide][range][concat_transform][observe_on][pythagorian][perf]"){ +SCENARIO("observe_on concat_transform pythagorian ranges", "[!hide][range][concat_transform][observe_on][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ @@ -150,7 +150,7 @@ SCENARIO("observe_on concat_transform pythagorian ranges", "[hide][range][concat } } -SCENARIO("serialize concat_transform pythagorian ranges", "[hide][range][concat_transform][serialize][pythagorian][perf]"){ +SCENARIO("serialize concat_transform pythagorian ranges", "[!hide][range][concat_transform][serialize][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ diff --git a/Rx/v2/test/operators/filter.cpp b/Rx/v2/test/operators/filter.cpp index 70c997b..08dd6ee 100644 --- a/Rx/v2/test/operators/filter.cpp +++ b/Rx/v2/test/operators/filter.cpp @@ -212,7 +212,9 @@ SCENARIO("filter stops on error", "[where][filter][operators]"){ } } -SCENARIO("filter stops on throw from predicate", "[where][filter][operators]"){ +// filter cannot possibly catch an exception when exceptions are disabled, +// so this test is meaningless when exceptions are disabled. +SCENARIO("filter stops on throw from predicate", "[where][filter][operators][!throws]"){ GIVEN("a test hot observable of ints"){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -248,7 +250,7 @@ SCENARIO("filter stops on throw from predicate", "[where][filter][operators]"){ .filter([ex, &invoked](int x) { invoked++; if (x > 5) { - throw ex; + rxu::throw_exception(ex); } return IsPrime(x); }) diff --git a/Rx/v2/test/operators/flat_map.cpp b/Rx/v2/test/operators/flat_map.cpp index 2e01a30..e1837b0 100644 --- a/Rx/v2/test/operators/flat_map.cpp +++ b/Rx/v2/test/operators/flat_map.cpp @@ -8,7 +8,7 @@ static const int static_tripletCount = 100; -SCENARIO("pythagorian for loops", "[hide][for][pythagorian][perf]"){ +SCENARIO("pythagorian for loops", "[!hide][for][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("a for loop"){ WHEN("generating pythagorian triplets"){ @@ -45,7 +45,7 @@ SCENARIO("pythagorian for loops", "[hide][for][pythagorian][perf]"){ } } -SCENARIO("merge_transform pythagorian ranges", "[hide][range][merge_transform][pythagorian][perf]"){ +SCENARIO("merge_transform pythagorian ranges", "[!hide][range][merge_transform][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ @@ -89,7 +89,7 @@ SCENARIO("merge_transform pythagorian ranges", "[hide][range][merge_transform][p } } -SCENARIO("synchronize merge_transform pythagorian ranges", "[hide][range][merge_transform][synchronize][pythagorian][perf]"){ +SCENARIO("synchronize merge_transform pythagorian ranges", "[!hide][range][merge_transform][synchronize][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ @@ -137,7 +137,7 @@ SCENARIO("synchronize merge_transform pythagorian ranges", "[hide][range][merge_ } } -SCENARIO("observe_on merge_transform pythagorian ranges", "[hide][range][merge_transform][observe_on][pythagorian][perf]"){ +SCENARIO("observe_on merge_transform pythagorian ranges", "[!hide][range][merge_transform][observe_on][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ @@ -185,7 +185,7 @@ SCENARIO("observe_on merge_transform pythagorian ranges", "[hide][range][merge_t } } -SCENARIO("serialize merge_transform pythagorian ranges", "[hide][range][merge_transform][serialize][pythagorian][perf]"){ +SCENARIO("serialize merge_transform pythagorian ranges", "[!hide][range][merge_transform][serialize][pythagorian][perf]"){ const int& tripletCount = static_tripletCount; GIVEN("some ranges"){ WHEN("generating pythagorian triplets"){ diff --git a/Rx/v2/test/operators/group_by.cpp b/Rx/v2/test/operators/group_by.cpp index 2c7c177..645bda4 100644 --- a/Rx/v2/test/operators/group_by.cpp +++ b/Rx/v2/test/operators/group_by.cpp @@ -9,8 +9,9 @@ #include <rxcpp/operators/rx-observe_on.hpp> #include <locale> +#include <sstream> -SCENARIO("range partitioned by group_by across hardware threads to derive pi", "[hide][pi][group_by][observe_on][long][perf]"){ +SCENARIO("range partitioned by group_by across hardware threads to derive pi", "[!hide][pi][group_by][observe_on][long][perf]"){ GIVEN("a for loop"){ WHEN("partitioning pi series across all hardware threads"){ @@ -92,7 +93,7 @@ SCENARIO("range partitioned by group_by across hardware threads to derive pi", " } } -SCENARIO("range partitioned by dividing work across hardware threads to derive pi", "[hide][pi][observe_on][long][perf]"){ +SCENARIO("range partitioned by dividing work across hardware threads to derive pi", "[!hide][pi][observe_on][long][perf]"){ GIVEN("a for loop"){ WHEN("partitioning pi series across all hardware threads"){ diff --git a/Rx/v2/test/operators/lift.cpp b/Rx/v2/test/operators/lift.cpp index 7d90bce..1f58c1d 100644 --- a/Rx/v2/test/operators/lift.cpp +++ b/Rx/v2/test/operators/lift.cpp @@ -31,17 +31,17 @@ struct liftfilter } void on_next(typename dest_type::value_type v) const { bool filtered = false; - try { + RXCPP_TRY { filtered = !test(v); - } catch(...) { - dest.on_error(std::current_exception()); + } RXCPP_CATCH(...) { + dest.on_error(rxu::current_exception()); return; } if (!filtered) { dest.on_next(v); } } - void on_error(std::exception_ptr e) const { + void on_error(rxu::error_ptr e) const { dest.on_error(e); } void on_completed() const { @@ -248,10 +248,10 @@ SCENARIO("lift lambda filter stops on disposal", "[where][filter][lift][lambda][ rx::make_observer_dynamic<int>( [=](int n){ bool pass = false; - try{pass = predicate(n);} catch(...){dest.on_error(std::current_exception());}; + RXCPP_TRY {pass = predicate(n);} RXCPP_CATCH(...){dest.on_error(rxu::current_exception());}; if (pass) {dest.on_next(n);} }, - [=](std::exception_ptr e){dest.on_error(e);}, + [=](rxu::error_ptr e){dest.on_error(e);}, [=](){dest.on_completed();})); }) // forget type to workaround lambda deduction bug on msvc 2013 diff --git a/Rx/v2/test/operators/merge.cpp b/Rx/v2/test/operators/merge.cpp index 9a7f28c..917d74d 100644 --- a/Rx/v2/test/operators/merge.cpp +++ b/Rx/v2/test/operators/merge.cpp @@ -6,7 +6,7 @@ const int static_onnextcalls = 1000000; -SCENARIO("synchronize merge ranges", "[hide][range][synchronize][merge][perf]"){ +SCENARIO("synchronize merge ranges", "[!hide][range][synchronize][merge][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("some ranges"){ WHEN("generating ints"){ @@ -34,7 +34,7 @@ SCENARIO("synchronize merge ranges", "[hide][range][synchronize][merge][perf]"){ } } -SCENARIO("observe_on merge ranges", "[hide][range][observe_on][merge][perf]"){ +SCENARIO("observe_on merge ranges", "[!hide][range][observe_on][merge][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("some ranges"){ WHEN("generating ints"){ @@ -62,7 +62,7 @@ SCENARIO("observe_on merge ranges", "[hide][range][observe_on][merge][perf]"){ } } -SCENARIO("serialize merge ranges", "[hide][range][serialize][merge][perf]"){ +SCENARIO("serialize merge ranges", "[!hide][range][serialize][merge][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("some ranges"){ WHEN("generating ints"){ diff --git a/Rx/v2/test/operators/merge_delay_error.cpp b/Rx/v2/test/operators/merge_delay_error.cpp index b53b884..83172ec 100644 --- a/Rx/v2/test/operators/merge_delay_error.cpp +++ b/Rx/v2/test/operators/merge_delay_error.cpp @@ -3,8 +3,6 @@ #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_delay_error completes", "[merge][join][operators]"){ diff --git a/Rx/v2/test/operators/observe_on.cpp b/Rx/v2/test/operators/observe_on.cpp index ffa85aa..aac2d40 100644 --- a/Rx/v2/test/operators/observe_on.cpp +++ b/Rx/v2/test/operators/observe_on.cpp @@ -5,7 +5,7 @@ const int static_onnextcalls = 100000; -SCENARIO("range observed on new_thread", "[hide][range][observe_on_debug][observe_on][long][perf]"){ +SCENARIO("range observed on new_thread", "[!hide][range][observe_on_debug][observe_on][long][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a range"){ WHEN("multicasting a million ints"){ diff --git a/Rx/v2/test/operators/on_error_resume_next.cpp b/Rx/v2/test/operators/on_error_resume_next.cpp index 3761094..e67b66e 100644 --- a/Rx/v2/test/operators/on_error_resume_next.cpp +++ b/Rx/v2/test/operators/on_error_resume_next.cpp @@ -30,7 +30,7 @@ SCENARIO("switch_on_error stops on completion", "[switch_on_error][on_error_resu auto res = w.start( [xs, ys, &invoked]() { return xs - .switch_on_error([ys, &invoked](std::exception_ptr) { + .switch_on_error([ys, &invoked](rxu::error_ptr) { invoked++; return ys; }) @@ -101,7 +101,7 @@ SCENARIO("on_error_resume_next stops on completion", "[on_error_resume_next][ope auto res = w.start( [xs, ys, &invoked]() { return xs - .on_error_resume_next([ys, &invoked](std::exception_ptr) { + .on_error_resume_next([ys, &invoked](rxu::error_ptr) { invoked++; return ys; }) @@ -174,7 +174,7 @@ SCENARIO("on_error_resume_next stops on error", "[on_error_resume_next][operator auto res = w.start( [xs, ys, &invoked]() { return xs - .on_error_resume_next([ys, &invoked](std::exception_ptr) { + .on_error_resume_next([ys, &invoked](rxu::error_ptr) { invoked++; return ys; }) diff --git a/Rx/v2/test/operators/publish.cpp b/Rx/v2/test/operators/publish.cpp index 87c8fff..c977597 100644 --- a/Rx/v2/test/operators/publish.cpp +++ b/Rx/v2/test/operators/publish.cpp @@ -4,7 +4,7 @@ #include <rxcpp/operators/rx-ref_count.hpp> -SCENARIO("publish range", "[hide][range][subject][publish][subject][operators]"){ +SCENARIO("publish range", "[!hide][range][subject][publish][subject][operators]"){ GIVEN("a range"){ WHEN("published"){ auto published = rxs::range<int>(0, 10).publish(); diff --git a/Rx/v2/test/operators/reduce.cpp b/Rx/v2/test/operators/reduce.cpp index 33a0644..46ad3cd 100644 --- a/Rx/v2/test/operators/reduce.cpp +++ b/Rx/v2/test/operators/reduce.cpp @@ -240,7 +240,11 @@ SCENARIO("max", "[reduce][max][operators]"){ } } -SCENARIO("max, empty", "[reduce][max][operators]"){ +// Does not work because calling max() on an empty stream throws an exception +// which will crash when exceptions are disabled. +// +// TODO: the max internal implementation should be rewritten not to throw exceptions. +SCENARIO("max, empty", "[reduce][max][operators][!throws]"){ GIVEN("a test hot observable of ints"){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -365,7 +369,10 @@ SCENARIO("min", "[reduce][min][operators]"){ } } -SCENARIO("min, empty", "[reduce][min][operators]"){ +// Does not work with exceptions disabled, min will throw when stream is empty +// and this crashes immediately. +// TODO: min implementation should be rewritten not to throw exceptions. +SCENARIO("min, empty", "[reduce][min][operators][!throws]"){ GIVEN("a test hot observable of ints"){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); diff --git a/Rx/v2/test/operators/scan.cpp b/Rx/v2/test/operators/scan.cpp index 5aa3c31..1cb38a5 100644 --- a/Rx/v2/test/operators/scan.cpp +++ b/Rx/v2/test/operators/scan.cpp @@ -3,7 +3,7 @@ #include <rxcpp/operators/rx-take.hpp> #include <rxcpp/operators/rx-scan.hpp> -SCENARIO("scan: issue 41", "[scan][operators][issue][hide]"){ +SCENARIO("scan: issue 41", "[scan][operators][issue][!hide]"){ GIVEN("map of scan of interval"){ auto sc = rxsc::make_current_thread(); auto so = rxcpp::synchronize_in_one_worker(sc); @@ -253,7 +253,7 @@ SCENARIO("scan: seed, some data", "[scan][operators]"){ } } -SCENARIO("scan: seed, accumulator throws", "[scan][operators]"){ +SCENARIO("scan: seed, accumulator throws", "[scan][operators][!throws]"){ GIVEN("a test hot observable of ints"){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -279,7 +279,7 @@ SCENARIO("scan: seed, accumulator throws", "[scan][operators]"){ return xs .scan(seed, [&](int sum, int x) { if (x == 4) { - throw ex; + rxu::throw_exception(ex); } return sum + x; }) diff --git a/Rx/v2/test/operators/subscribe_on.cpp b/Rx/v2/test/operators/subscribe_on.cpp index baa66e2..ef8a8c7 100644 --- a/Rx/v2/test/operators/subscribe_on.cpp +++ b/Rx/v2/test/operators/subscribe_on.cpp @@ -4,9 +4,11 @@ #include <rxcpp/operators/rx-subscribe_on.hpp> #include <rxcpp/operators/rx-observe_on.hpp> +#include <sstream> + static const int static_subscriptions = 50000; -SCENARIO("for loop subscribes to map with subscribe_on and observe_on", "[hide][for][just][subscribe][subscribe_on][observe_on][long][perf]"){ +SCENARIO("for loop subscribes to map with subscribe_on and observe_on", "[!hide][for][just][subscribe][subscribe_on][observe_on][long][perf]"){ const int& subscriptions = static_subscriptions; GIVEN("a for loop"){ WHEN("subscribe 50K times"){ @@ -46,7 +48,7 @@ SCENARIO("for loop subscribes to map with subscribe_on and observe_on", "[hide][ } } -SCENARIO("for loop subscribes to map with subscribe_on", "[hide][subscribe_on_only][for][just][subscribe][subscribe_on][long][perf]"){ +SCENARIO("for loop subscribes to map with subscribe_on", "[!hide][subscribe_on_only][for][just][subscribe][subscribe_on][long][perf]"){ const int& subscriptions = static_subscriptions; GIVEN("a for loop"){ WHEN("subscribe 50K times"){ diff --git a/Rx/v2/test/operators/tap.cpp b/Rx/v2/test/operators/tap.cpp index 9aad159..c9e8317 100644 --- a/Rx/v2/test/operators/tap.cpp +++ b/Rx/v2/test/operators/tap.cpp @@ -86,7 +86,7 @@ SCENARIO("tap stops on error", "[tap][operators]"){ auto res = w.start( [xs, &invoked]() { return xs - .tap([&invoked](std::exception_ptr) { + .tap([&invoked](rxu::error_ptr) { invoked++; }) // forget type to workaround lambda deduction bug on msvc 2013 diff --git a/Rx/v2/test/operators/with_latest_from.cpp b/Rx/v2/test/operators/with_latest_from.cpp index 4d03641..ae7092a 100644 --- a/Rx/v2/test/operators/with_latest_from.cpp +++ b/Rx/v2/test/operators/with_latest_from.cpp @@ -1463,7 +1463,7 @@ SCENARIO("with_latest_from error after completed right", "[with_latest_from][joi } } -SCENARIO("with_latest_from selector throws", "[with_latest_from][join][operators]"){ +SCENARIO("with_latest_from selector throws", "[with_latest_from][join][operators][!throws]"){ GIVEN("2 hot observables of ints."){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -1490,7 +1490,7 @@ SCENARIO("with_latest_from selector throws", "[with_latest_from][join][operators return o2 .with_latest_from( [&ex](int, int) -> int { - throw ex; + rxu::throw_exception(ex); }, o1 ) @@ -1526,7 +1526,7 @@ SCENARIO("with_latest_from selector throws", "[with_latest_from][join][operators } } -SCENARIO("with_latest_from selector throws N", "[with_latest_from][join][operators]"){ +SCENARIO("with_latest_from selector throws N", "[with_latest_from][join][operators][!throws]"){ GIVEN("N hot observables of ints."){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -1553,7 +1553,7 @@ SCENARIO("with_latest_from selector throws N", "[with_latest_from][join][operato return e[3] .with_latest_from( [&ex](int, int, int, int) -> int { - throw ex; + rxu::throw_exception(ex); }, e[0], e[1], e[2] ) diff --git a/Rx/v2/test/operators/zip.cpp b/Rx/v2/test/operators/zip.cpp index 1bbdd86..c048006 100644 --- a/Rx/v2/test/operators/zip.cpp +++ b/Rx/v2/test/operators/zip.cpp @@ -1185,7 +1185,7 @@ SCENARIO("zip right completes first", "[zip][join][operators]"){ } } -SCENARIO("zip selector throws", "[zip][join][operators]"){ +SCENARIO("zip selector throws", "[zip][join][operators][!throws]"){ GIVEN("2 hot observables of ints."){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -1212,7 +1212,7 @@ SCENARIO("zip selector throws", "[zip][join][operators]"){ return o1 .zip( [&ex](int, int) -> int { - throw ex; + rxu::throw_exception(ex); }, o2 ) @@ -1248,7 +1248,7 @@ SCENARIO("zip selector throws", "[zip][join][operators]"){ } } -SCENARIO("zip selector throws N", "[zip][join][operators]"){ +SCENARIO("zip selector throws N", "[zip][join][operators][!throws]"){ GIVEN("N hot observables of ints."){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -1275,7 +1275,7 @@ SCENARIO("zip selector throws N", "[zip][join][operators]"){ return e[0] .zip( [&ex](int, int, int, int) -> int { - throw ex; + rxu::throw_exception(ex); }, e[1], e[2], e[3] ) diff --git a/Rx/v2/test/sources/defer.cpp b/Rx/v2/test/sources/defer.cpp index 266380e..a8187ad 100644 --- a/Rx/v2/test/sources/defer.cpp +++ b/Rx/v2/test/sources/defer.cpp @@ -15,7 +15,7 @@ SCENARIO("defer stops on completion", "[defer][sources]"){ auto empty = rx::observable<>::empty<long>(); auto just = rx::observable<>::just(42); auto one = rx::observable<>::from(42); - auto error = rx::observable<>::error<long>(std::exception_ptr()); + auto error = rx::observable<>::error<long>(rxu::error_ptr()); auto runtimeerror = rx::observable<>::error<long>(std::runtime_error("runtime")); auto res = w.start( diff --git a/Rx/v2/test/sources/interval.cpp b/Rx/v2/test/sources/interval.cpp index 38f4ac3..9ab2fca 100644 --- a/Rx/v2/test/sources/interval.cpp +++ b/Rx/v2/test/sources/interval.cpp @@ -1,6 +1,6 @@ #include "../test.h" -SCENARIO("schedule_periodically", "[hide][periodically][scheduler][long][perf][sources]"){ +SCENARIO("schedule_periodically", "[!hide][periodically][scheduler][long][perf][sources]"){ GIVEN("schedule_periodically"){ WHEN("the period is 1sec and the initial is 2sec"){ using namespace std::chrono; @@ -21,7 +21,7 @@ SCENARIO("schedule_periodically", "[hide][periodically][scheduler][long][perf][s } } -SCENARIO("schedule_periodically by duration", "[hide][periodically][scheduler][long][perf][sources]"){ +SCENARIO("schedule_periodically by duration", "[!hide][periodically][scheduler][long][perf][sources]"){ GIVEN("schedule_periodically_duration"){ WHEN("the period is 1sec and the initial is 2sec"){ using namespace std::chrono; @@ -64,7 +64,7 @@ SCENARIO("schedule_periodically by duration", "[hide][periodically][scheduler][l } } -SCENARIO("intervals", "[hide][periodically][interval][scheduler][long][perf][sources]"){ +SCENARIO("intervals", "[!hide][periodically][interval][scheduler][long][perf][sources]"){ GIVEN("10 intervals of 1 seconds"){ WHEN("the period is 1sec and the initial is 2sec"){ using namespace std::chrono; @@ -84,7 +84,7 @@ SCENARIO("intervals", "[hide][periodically][interval][scheduler][long][perf][sou std::cout << "interval : period " << counter << ", " << nsDelta.count() << "ms delta from target time" << std::endl; if (counter == 5) {cs.unsubscribe();} }, - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); } } } diff --git a/Rx/v2/test/sources/scope.cpp b/Rx/v2/test/sources/scope.cpp index 383544b..1389344 100644 --- a/Rx/v2/test/sources/scope.cpp +++ b/Rx/v2/test/sources/scope.cpp @@ -318,7 +318,7 @@ SCENARIO("scope, dispose", "[scope][sources]"){ } } -SCENARIO("scope, throw resource selector", "[scope][sources]"){ +SCENARIO("scope, throw resource selector", "[scope][sources][!throws]"){ GIVEN("a test cold observable of ints"){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -339,7 +339,7 @@ SCENARIO("scope, throw resource selector", "[scope][sources]"){ scope( [&]() -> resource { ++resource_factory_invoked; - throw ex; + rxu::throw_exception(ex); //return resource(sc.clock()); }, [&](resource){ @@ -371,7 +371,7 @@ SCENARIO("scope, throw resource selector", "[scope][sources]"){ } } -SCENARIO("scope, throw resource usage", "[scope][sources]"){ +SCENARIO("scope, throw resource usage", "[scope][sources][!throws]"){ GIVEN("a test cold observable of ints"){ auto sc = rxsc::make_test(); auto w = sc.create_worker(); @@ -396,7 +396,7 @@ SCENARIO("scope, throw resource usage", "[scope][sources]"){ }, [&](resource) -> rx::observable<int> { ++observable_factory_invoked; - throw ex; + rxu::throw_exception(ex); } ) // forget type to workaround lambda deduction bug on msvc 2013 diff --git a/Rx/v2/test/sources/timer.cpp b/Rx/v2/test/sources/timer.cpp index 9141f2e..3f46b21 100644 --- a/Rx/v2/test/sources/timer.cpp +++ b/Rx/v2/test/sources/timer.cpp @@ -1,6 +1,6 @@ #include "../test.h" -SCENARIO("timer", "[hide][periodically][timer][scheduler][long][perf][sources]"){ +SCENARIO("timer", "[!hide][periodically][timer][scheduler][long][perf][sources]"){ GIVEN("the timer of 1 sec"){ WHEN("the period is 1 sec"){ using namespace std::chrono; @@ -17,7 +17,7 @@ SCENARIO("timer", "[hide][periodically][timer][scheduler][long][perf][sources]") auto nsDelta = duration_cast<milliseconds>(sc.now() - (start + (period * counter))); std::cout << "timer : period " << counter << ", " << nsDelta.count() << "ms delta from target time" << std::endl; }, - [](std::exception_ptr){abort();}, + [](rxu::error_ptr){abort();}, [](){std::cout << "completed" << std::endl;}); } } diff --git a/Rx/v2/test/subjects/subject.cpp b/Rx/v2/test/subjects/subject.cpp index b6c6d67..09318a3 100644 --- a/Rx/v2/test/subjects/subject.cpp +++ b/Rx/v2/test/subjects/subject.cpp @@ -10,7 +10,7 @@ const int static_onnextcalls = 10000000; static int aliased = 0; -SCENARIO("for loop locks mutex", "[hide][for][mutex][long][perf]"){ +SCENARIO("for loop locks mutex", "[!hide][for][mutex][long][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a for loop"){ WHEN("locking mutex 100 million times"){ @@ -52,7 +52,7 @@ public: } }; } -SCENARIO("for loop calls void on_next(int)", "[hide][for][asyncobserver][baseline][perf]"){ +SCENARIO("for loop calls void on_next(int)", "[!hide][for][asyncobserver][baseline][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a for loop"){ WHEN("calling on_next 100 million times"){ @@ -137,7 +137,7 @@ public: } }; } -SCENARIO("for loop calls ready on_next(int)", "[hide][for][asyncobserver][ready][perf]"){ +SCENARIO("for loop calls ready on_next(int)", "[!hide][for][asyncobserver][ready][perf]"){ static const int& onnextcalls = static_onnextcalls; GIVEN("a for loop"){ WHEN("calling on_next 100 million times"){ @@ -191,7 +191,7 @@ public: onnext(v); return ready.get_future();} }; } -SCENARIO("for loop calls std::future<unit> on_next(int)", "[hide][for][asyncobserver][future][long][perf]"){ +SCENARIO("for loop calls std::future<unit> on_next(int)", "[!hide][for][asyncobserver][future][long][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a for loop"){ WHEN("calling on_next 100 million times"){ @@ -218,7 +218,7 @@ SCENARIO("for loop calls std::future<unit> on_next(int)", "[hide][for][asyncobse } } -SCENARIO("for loop calls observer", "[hide][for][observer][perf]"){ +SCENARIO("for loop calls observer", "[!hide][for][observer][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a for loop"){ WHEN("observing 100 million ints"){ @@ -232,7 +232,7 @@ SCENARIO("for loop calls observer", "[hide][for][observer][perf]"){ auto start = clock::now(); auto o = rx::make_observer<int>( [](int){++c;}, - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); for (int i = 0; i < onnextcalls; i++) { o.on_next(i); } @@ -244,7 +244,7 @@ SCENARIO("for loop calls observer", "[hide][for][observer][perf]"){ } } -SCENARIO("for loop calls subscriber", "[hide][for][subscriber][perf]"){ +SCENARIO("for loop calls subscriber", "[!hide][for][subscriber][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a for loop"){ WHEN("observing 100 million ints"){ @@ -258,7 +258,7 @@ SCENARIO("for loop calls subscriber", "[hide][for][subscriber][perf]"){ auto start = clock::now(); auto o = rx::make_subscriber<int>( [](int){++c;}, - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); for (int i = 0; i < onnextcalls && o.is_subscribed(); i++) { o.on_next(i); } @@ -270,7 +270,7 @@ SCENARIO("for loop calls subscriber", "[hide][for][subscriber][perf]"){ } } -SCENARIO("range calls subscriber", "[hide][range][subscriber][perf]"){ +SCENARIO("range calls subscriber", "[!hide][range][subscriber][perf]"){ const int& onnextcalls = static_onnextcalls; GIVEN("a range"){ WHEN("observing 100 million ints"){ @@ -287,7 +287,7 @@ SCENARIO("range calls subscriber", "[hide][range][subscriber][perf]"){ [](int){ ++c; }, - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); auto finish = clock::now(); auto msElapsed = duration_cast<milliseconds>(finish-start); @@ -296,7 +296,7 @@ SCENARIO("range calls subscriber", "[hide][range][subscriber][perf]"){ } } -SCENARIO("for loop calls subject", "[hide][for][subject][subjects][long][perf]"){ +SCENARIO("for loop calls subject", "[!hide][for][subject][subjects][long][perf]"){ static const int& onnextcalls = static_onnextcalls; GIVEN("a for loop and a subject"){ WHEN("multicasting a million ints"){ @@ -337,7 +337,7 @@ SCENARIO("for loop calls subject", "[hide][for][subject][subjects][long][perf]") [cs](int){ cs.unsubscribe(); }, - [](std::exception_ptr){abort();})); + [](rxu::error_ptr){abort();})); } return 0; }); @@ -346,7 +346,7 @@ SCENARIO("for loop calls subject", "[hide][for][subject][subjects][long][perf]") [c, p](int){ ++(*c); }, - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); } auto start = clock::now(); @@ -370,7 +370,7 @@ SCENARIO("for loop calls subject", "[hide][for][subject][subjects][long][perf]") } } -SCENARIO("range calls subject", "[hide][range][subject][subjects][long][perf]"){ +SCENARIO("range calls subject", "[!hide][range][subject][subjects][long][perf]"){ static const int& onnextcalls = static_onnextcalls; GIVEN("a range and a subject"){ WHEN("multicasting a million ints"){ @@ -407,7 +407,7 @@ SCENARIO("range calls subject", "[hide][range][subject][subjects][long][perf]"){ [cs](int){ cs.unsubscribe(); }, - [](std::exception_ptr){abort();}); + [](rxu::error_ptr){abort();}); } return 0; }); @@ -417,7 +417,7 @@ SCENARIO("range calls subject", "[hide][range][subject][subjects][long][perf]"){ [c, p](int){ ++(*c); }, - [](std::exception_ptr){abort();} + [](rxu::error_ptr){abort();} ); } diff --git a/Rx/v2/test/subscriptions/coroutine.cpp b/Rx/v2/test/subscriptions/coroutine.cpp index bf67c55..d678714 100644 --- a/Rx/v2/test/subscriptions/coroutine.cpp +++ b/Rx/v2/test/subscriptions/coroutine.cpp @@ -24,13 +24,13 @@ SCENARIO("coroutine completes", "[coroutine]"){ w.advance_to(rxsc::test::subscribed_time); auto d = [&]() -> std::future<void> { - try { + RXCPP_TRY { for co_await (auto n : xs | rxo::as_dynamic()) { messages.push_back(on.next(w.clock(), n)); } messages.push_back(on.completed(w.clock())); - } catch (...) { - messages.push_back(on.error(w.clock(), std::current_exception())); + } RXCPP_CATCH(...) { + messages.push_back(on.error(w.clock(), rxu::current_exception())); } }(); @@ -85,13 +85,13 @@ SCENARIO("coroutine errors", "[coroutine]"){ w.advance_to(rxsc::test::subscribed_time); auto d = [&]() -> std::future<void> { - try { + RXCPP_TRY { for co_await (auto n : xs | rxo::as_dynamic()) { messages.push_back(on.next(w.clock(), n)); } messages.push_back(on.completed(w.clock())); - } catch (...) { - messages.push_back(on.error(w.clock(), std::current_exception())); + } RXCPP_CATCH(...) { + messages.push_back(on.error(w.clock(), rxu::current_exception())); } }(); diff --git a/Rx/v2/test/subscriptions/observer.cpp b/Rx/v2/test/subscriptions/observer.cpp index 57d4ad1..894e610 100644 --- a/Rx/v2/test/subscriptions/observer.cpp +++ b/Rx/v2/test/subscriptions/observer.cpp @@ -4,7 +4,7 @@ SCENARIO("subscriber traits", "[observer][traits]"){ GIVEN("given some subscriber types"){ int result = 0; auto next = [&result](int i){result += i;}; - auto error = [&result](std::exception_ptr){result += 10;}; + auto error = [&result](rxu::error_ptr){result += 10;}; auto completed = [&result](){result += 100;}; // auto ra = rx::rxu::detail::arg_resolver_n<0, rx::tag_resumption_resolution::template predicate, typename rx::tag_resumption_resolution::default_type, rx::resumption, decltype(next), decltype(error), decltype(completed), rx::rxu::detail::tag_unresolvable, rx::rxu::detail::tag_unresolvable>(rx::resumption(), next, error, completed, rx::rxu::detail::tag_unresolvable(), rx::rxu::detail::tag_unresolvable()); // auto ra = typename rx::rxu::detail::arg_resolver<rx::tag_resumption_resolution::template predicate, typename rx::tag_resumption_resolution::default_type, rx::resumption, decltype(next), decltype(error), decltype(completed)>::type(rx::resumption(), next, error, completed, rx::rxu::detail::tag_unresolvable(), rx::rxu::detail::tag_unresolvable()); @@ -45,7 +45,7 @@ SCENARIO("subscriber traits", "[observer][traits]"){ } WHEN("after error"){ THEN("subscriber result is 10"){ - scrbResult.on_error(std::current_exception()); + scrbResult.on_error(rxu::current_exception()); REQUIRE(result == 10); } } @@ -102,7 +102,7 @@ SCENARIO("subscriber behavior", "[observer][traits]"){ GIVEN("given some subscriber types"){ int result = 0; auto next = [&result](int i){result += i;}; - auto error = [&result](std::exception_ptr){result += 10;}; + auto error = [&result](rxu::error_ptr){result += 10;}; auto completed = [&result](){result += 100;}; auto dob = rx::make_subscriber<int>(rx::make_observer_dynamic<int>(next, error, completed)); auto so = rx::make_subscriber<int>(next, error, completed); @@ -143,19 +143,19 @@ SCENARIO("subscriber behavior", "[observer][traits]"){ } WHEN("after error"){ THEN("dynamic_observer result is 10"){ - dob.on_error(std::current_exception()); + dob.on_error(rxu::current_exception()); REQUIRE(result == 10); } THEN("static_observer result is 10"){ - so.on_error(std::current_exception()); + so.on_error(rxu::current_exception()); REQUIRE(result == 10); } THEN("dynamic_observer is not subscribed"){ - dob.on_error(std::current_exception()); + dob.on_error(rxu::current_exception()); REQUIRE(!dob.is_subscribed()); } THEN("static_observer is not subscribed"){ - so.on_error(std::current_exception()); + so.on_error(rxu::current_exception()); REQUIRE(!so.is_subscribed()); } } diff --git a/Rx/v2/test/subscriptions/subscription.cpp b/Rx/v2/test/subscriptions/subscription.cpp index 2a9f15d..33218a7 100644 --- a/Rx/v2/test/subscriptions/subscription.cpp +++ b/Rx/v2/test/subscriptions/subscription.cpp @@ -6,7 +6,9 @@ #include "rxcpp/operators/rx-publish.hpp" #include "rxcpp/operators/rx-ref_count.hpp" -SCENARIO("observe subscription", "[hide]"){ +#include <sstream> + +SCENARIO("observe subscription", "[!hide]"){ GIVEN("observable of ints"){ WHEN("subscribe"){ auto observers = std::make_shared<std::list<rxcpp::subscriber<int>>>(); @@ -24,7 +26,7 @@ SCENARIO("observe subscription", "[hide]"){ static const int static_subscriptions = 10000; -SCENARIO("for loop subscribes to map", "[hide][for][just][subscribe][long][perf]"){ +SCENARIO("for loop subscribes to map", "[!hide][for][just][subscribe][long][perf]"){ const int& subscriptions = static_subscriptions; GIVEN("a for loop"){ WHEN("subscribe 100K times"){ @@ -69,7 +71,7 @@ SCENARIO("for loop subscribes to map", "[hide][for][just][subscribe][long][perf] } } -SCENARIO("for loop subscribes to combine_latest", "[hide][for][just][combine_latest][subscribe][long][perf]"){ +SCENARIO("for loop subscribes to combine_latest", "[!hide][for][just][combine_latest][subscribe][long][perf]"){ const int& subscriptions = static_subscriptions; GIVEN("a for loop"){ WHEN("subscribe 100K times"){ @@ -107,7 +109,7 @@ SCENARIO("for loop subscribes to combine_latest", "[hide][for][just][combine_lat } } -SCENARIO("synchronized range debug", "[hide][subscribe][range][synchronize_debug][synchronize][long][perf]"){ +SCENARIO("synchronized range debug", "[!hide][subscribe][range][synchronize_debug][synchronize][long][perf]"){ GIVEN("range"){ WHEN("synchronized"){ using namespace std::chrono; @@ -139,7 +141,7 @@ SCENARIO("synchronized range debug", "[hide][subscribe][range][synchronize_debug ++std::get<1>(*completionstate); std::get<2>(*completionstate).on_next(n); }, - [=](std::exception_ptr){ + [=](rxu::error_ptr){ abort(); }, [=](){ @@ -216,7 +218,7 @@ SCENARIO("synchronized range debug", "[hide][subscribe][range][synchronize_debug } } -SCENARIO("observe_on range debug", "[hide][subscribe][range][observe_on_debug][observe_on][long][perf]"){ +SCENARIO("observe_on range debug", "[!hide][subscribe][range][observe_on_debug][observe_on][long][perf]"){ GIVEN("range"){ WHEN("observed on"){ using namespace std::chrono; @@ -248,7 +250,7 @@ SCENARIO("observe_on range debug", "[hide][subscribe][range][observe_on_debug][o ++std::get<1>(*completionstate); std::get<2>(*completionstate).on_next(n); }, - [=](std::exception_ptr){ + [=](rxu::error_ptr){ abort(); }, [=](){ diff --git a/appveyor.yml b/appveyor.yml index 68ea434..42882b2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,8 +10,6 @@ image: Visual Studio 2017 environment: matrix: - - 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 diff --git a/ext/catch b/ext/catch -Subproject ad942885ceab72d421fc6b07aedf0c012ef90e4 +Subproject 9e1bdca4667295fcb16265eae00efa8423f0700 diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt index 542a91a..d15c57f 100644 --- a/projects/CMake/CMakeLists.txt +++ b/projects/CMake/CMakeLists.txt @@ -59,6 +59,7 @@ set(RX_SOURCES ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-ref_count.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-repeat.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-replay.hpp + ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-retry-repeat-common.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-retry.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-sample_time.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-scan.hpp @@ -83,13 +84,16 @@ set(RX_SOURCES ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-with_latest_from.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-window.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-window_time.hpp + ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-window_toggle.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-window_time_count.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/operators/rx-zip.hpp + ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-composite_exception.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-connectable_observable.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-coordination.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-coroutine.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-grouped_observable.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-includes.hpp + ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-lite.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-notification.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-observable.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/rx-observer.hpp @@ -114,6 +118,7 @@ set(RX_SOURCES ${RXCPP_DIR}/Rx/v2/src/rxcpp/schedulers/rx-virtualtime.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/sources/rx-create.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/sources/rx-defer.hpp + ${RXCPP_DIR}/Rx/v2/src/rxcpp/sources/rx-empty.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/sources/rx-error.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/sources/rx-interval.hpp ${RXCPP_DIR}/Rx/v2/src/rxcpp/sources/rx-iterate.hpp diff --git a/projects/CMake/shared.cmake b/projects/CMake/shared.cmake index ac0d09c..f7f7a31 100644 --- a/projects/CMake/shared.cmake +++ b/projects/CMake/shared.cmake @@ -1,5 +1,7 @@ FIND_PACKAGE(Threads) +option(RX_USE_EXCEPTIONS "Use C++ exceptions" ON) + # define some compiler settings MESSAGE( STATUS "CMAKE_CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID} ) @@ -13,13 +15,21 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") -Wno-error=unused-command-line-argument -ftemplate-depth=1024 ) + if (NOT RX_USE_EXCEPTIONS) + MESSAGE( STATUS "no exceptions" ) + list(APPEND RX_COMPILE_OPTIONS -fno-exceptions) + endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU") MESSAGE( STATUS "gnu compiler version: " ${CMAKE_CXX_COMPILER_VERSION} ) MESSAGE( STATUS "using gnu settings" ) set(RX_COMPILE_OPTIONS -Wall -Wextra -Werror -Wunused ) -elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + if (NOT RX_USE_EXCEPTIONS) + MESSAGE( STATUS "no exceptions" ) + list(APPEND RX_COMPILE_OPTIONS -fno-exceptions) + endif() + elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") MESSAGE( STATUS "msvc compiler version: " ${CMAKE_CXX_COMPILER_VERSION} ) MESSAGE( STATUS "using msvc settings" ) set(RX_COMPILE_OPTIONS @@ -29,9 +39,13 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") /bigobj /DUNICODE /D_UNICODE # it is a new millenium ) + if (NOT RX_USE_EXCEPTIONS) + MESSAGE( STATUS "no exceptions" ) + list(APPEND RX_COMPILE_OPTIONS /EHs-c-) + endif() if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.23506.0") - set(RX_COMPILE_OPTIONS - ${RX_COMPILE_OPTIONS} + MESSAGE( STATUS "with coroutines" ) + list(APPEND RX_COMPILE_OPTIONS /await # enable coroutines ) endif() @@ -54,4 +68,4 @@ set(RX_COMPILE_FEATURES set(IX_SRC_DIR ${RXCPP_DIR}/Ix/CPP/src) set(RX_SRC_DIR ${RXCPP_DIR}/Rx/v2/src) -set(RX_CATCH_DIR ${RXCPP_DIR}/ext/catch/include) +set(RX_CATCH_DIR ${RXCPP_DIR}/ext/catch/single_include/catch2) |