Skip to content

Commit

Permalink
Add on_error_resume_next operator (#528)
Browse files Browse the repository at this point in the history
  • Loading branch information
CorentinBT authored Feb 18, 2024
1 parent 09b74b8 commit 151959c
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/benchmarks/benchmarks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,30 @@ int main(int argc, char* argv[]) // NOLINT(bugprone-exception-escape)
}
} // BENCHMARK("Aggregating Operators")

BENCHMARK("Error Handling Operators")
{
SECTION("create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe")
{
TEST_RPP([&]() {
rpp::source::create<int>([&](auto&& observer) {
observer.on_next(1);
observer.on_error(std::make_exception_ptr(std::runtime_error{""}));
})
| rpp::operators::on_error_resume_next([](const std::exception_ptr&) { return rpp::immediate_just(2); })
| rpp::operators::subscribe([](int v) { ankerl::nanobench::doNotOptimizeAway(v); });
});

TEST_RXCPP([&]() {
rxcpp::observable<>::create<int>([&](auto&& observer) {
observer.on_next(1);
observer.on_error(std::make_exception_ptr(std::runtime_error{""}));
})
| rxcpp::operators::on_error_resume_next([](const std::exception_ptr&) { return rxcpp::immediate_just(2); })
| rxcpp::operators::subscribe<int>([](int v) { ankerl::nanobench::doNotOptimizeAway(v); });
});
}
} // BENCHMARK("Error Handling Operators")

BENCHMARK("Subjects")
{
SECTION("publish_subject with 1 observer - on_next")
Expand Down
9 changes: 9 additions & 0 deletions src/rpp/rpp/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,12 @@

#include <rpp/operators/concat.hpp>
#include <rpp/operators/reduce.hpp>

/**
* @defgroup error_handling_operators Error Handling Operators
* @brief Operators that help to recover from error notifications from an Observable
* @see https://reactivex.io/documentation/operators.html#error
* @ingroup operators
*/

#include <rpp/operators/on_error_resume_next.hpp>
109 changes: 109 additions & 0 deletions src/rpp/rpp/operators/on_error_resume_next.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// ReactivePlusPlus library
//
// Copyright Aleksey Loginov 2023 - present.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/victimsnino/ReactivePlusPlus
//

#pragma once

#include <rpp/operators/fwd.hpp>

#include <rpp/defs.hpp>
#include <rpp/operators/details/strategy.hpp>

namespace rpp::operators::details
{
template<rpp::constraint::observer TObserver, rpp::constraint::decayed_type Selector>
struct on_error_resume_next_observer_strategy
{
using preferred_disposable_strategy = rpp::details::observers::none_disposable_strategy;

RPP_NO_UNIQUE_ADDRESS mutable TObserver observer;
RPP_NO_UNIQUE_ADDRESS Selector selector;
// Manually control disposable to ensure observer is not used after move in on_error emission
mutable rpp::composite_disposable_wrapper disposable = composite_disposable_wrapper::make();

RPP_CALL_DURING_CONSTRUCTION(
{
observer.set_upstream(disposable);
});

template<typename T>
void on_next(T&& v) const
{
observer.on_next(std::forward<T>(v));
}

void on_error(const std::exception_ptr& err) const
{
disposable.dispose();
selector(err).subscribe(std::move(observer));
}

void on_completed() const
{
disposable.dispose();
observer.on_completed();
}

void set_upstream(const disposable_wrapper& d)
{
disposable.add(d);
}

bool is_disposed() const { return disposable.is_disposed(); }
};

template<rpp::constraint::decayed_type Selector>
struct on_error_resume_next_t : lift_operator<on_error_resume_next_t<Selector>, Selector>
{
template<rpp::constraint::decayed_type T>
struct operator_traits
{
using selector_observable_result_type =
rpp::utils::extract_observable_type_t<std::invoke_result_t<Selector, std::exception_ptr>>;

static_assert(
rpp::constraint::decayed_same_as<selector_observable_result_type, T>,
"Selector observable result type is not the same as T");

using result_type = T;

template<rpp::constraint::observer_of_type<result_type> TObserver>
using observer_strategy = on_error_resume_next_observer_strategy<TObserver, Selector>;
};

template<rpp::details::observables::constraint::disposable_strategy Prev>
using updated_disposable_strategy = rpp::details::observables::atomic_dynamic_disposable_strategy_selector<1>;
};
} // namespace rpp::operators::details

namespace rpp::operators
{
/**
* @brief If an error occurs, take the result from the Selector and subscribe to that instead.
*
* @marble on_error_resume_next
{
source observable : +-1-x
operator "on_error_resume_next: () => obs(-2-3-|)" : +-1-2-3-|
}
*
* @param selector callable taking a std::exception_ptr and returning observable to continue on
*
* @warning #include <rpp/operators/on_error_resume_next.hpp>
*
* @ingroup error_handling_operators
* @see https://reactivex.io/documentation/operators/catch.html
*/
template<typename Selector>
requires rpp::constraint::observable<std::invoke_result_t<Selector, std::exception_ptr>>
auto on_error_resume_next(Selector&& selector)
{
return details::on_error_resume_next_t<std::decay_t<Selector>>{std::forward<Selector>(selector)};
}
} // namespace rpp::operators
156 changes: 156 additions & 0 deletions src/tests/rpp/test_on_error_resume_next.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// ReactivePlusPlus library
//
// Copyright Aleksey Loginov 2023 - present.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/victimsnino/ReactivePlusPlus
//

#include <snitch/snitch.hpp>

#include <rpp/operators/on_error_resume_next.hpp>
#include <rpp/schedulers/immediate.hpp>
#include <rpp/sources/create.hpp>
#include <rpp/sources/empty.hpp>
#include <rpp/sources/just.hpp>

#include "disposable_observable.hpp"
#include "mock_observer.hpp"

TEMPLATE_TEST_CASE("on_error_resume_next switches observable on error", "", rpp::memory_model::use_stack, rpp::memory_model::use_shared)
{
auto mock = mock_observer_strategy<int>();
SECTION("observable without error emission")
{
auto obs = rpp::source::just<TestType>(rpp::schedulers::immediate{}, 1, 2, 3);
SECTION("subscribe")
{
obs | rpp::operators::on_error_resume_next([](const std::exception_ptr&) { return rpp::source::empty<int>(); })
| rpp::ops::subscribe(mock);
SECTION("observer obtains values from observable")
{
CHECK(mock.get_received_values() == std::vector{1, 2, 3});
CHECK(mock.get_total_on_next_count() == 3);
CHECK(mock.get_on_error_count() == 0);
CHECK(mock.get_on_completed_count() == 1);
}
}
}

SECTION("observable with one error emission")
{
auto obs = rpp::source::create<int>([](const auto& sub) {
sub.on_next(1);
sub.on_next(2);
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
});
SECTION("subscribe")
{
obs | rpp::operators::on_error_resume_next([](const std::exception_ptr&) {
return rpp::source::just<TestType>(rpp::schedulers::immediate{}, 3);
})
| rpp::ops::subscribe(mock);
SECTION("observer obtains values from both outer and inner observable")
{
CHECK(mock.get_received_values() == std::vector{1, 2, 3});
CHECK(mock.get_total_on_next_count() == 3);
CHECK(mock.get_on_error_count() == 0);
CHECK(mock.get_on_completed_count() == 1);
}
}
}

SECTION("observable with two error emissions")
{
auto obs = rpp::source::create<int>([](const auto& sub) {
sub.on_next(1);
sub.on_next(2);
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
});
SECTION("subscribe")
{
obs | rpp::operators::on_error_resume_next([](const std::exception_ptr&) {
return rpp::source::just<TestType>(rpp::schedulers::immediate{}, 3);
})
| rpp::ops::subscribe(mock);
SECTION("observer only receives values from first inner observable")
{
CHECK(mock.get_received_values() == std::vector{1, 2, 3});
CHECK(mock.get_total_on_next_count() == 3);
CHECK(mock.get_on_error_count() == 0);
CHECK(mock.get_on_completed_count() == 1);
}
}
}

SECTION("inner observable different emission type")
{
auto obs = rpp::source::create<int>([](const auto& sub) {
sub.on_next(1);
sub.on_next(2);
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
});
SECTION("subscribe")
{
obs | rpp::operators::on_error_resume_next([](const std::exception_ptr&) {
return rpp::source::just<TestType>(rpp::schedulers::immediate{}, 3);
})
| rpp::ops::subscribe(mock);
SECTION("observer only receives values from first inner observable")
{
CHECK(mock.get_received_values() == std::vector{1, 2, 3});
CHECK(mock.get_total_on_next_count() == 3);
CHECK(mock.get_on_error_count() == 0);
CHECK(mock.get_on_completed_count() == 1);
}
}
}

SECTION("nested on_error_resume_next operators")
{
auto obs = rpp::source::create<int>([](const auto& sub) {
sub.on_next(1);
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
});
SECTION("subscribe")
{
obs | rpp::operators::on_error_resume_next([](const std::exception_ptr&) {
return rpp::source::create<int>([](const auto& sub) {
sub.on_next(2);
sub.on_error(std::make_exception_ptr(std::runtime_error{""}));
})
| rpp::operators::on_error_resume_next([](const std::exception_ptr&) {
return rpp::source::create<int>([](const auto& sub) {
sub.on_next(3);
sub.on_completed();
});
});
})
| rpp::ops::subscribe(mock);
SECTION("observer receives values without any errors")
{
CHECK(mock.get_received_values() == std::vector{1, 2, 3});
CHECK(mock.get_total_on_next_count() == 3);
CHECK(mock.get_on_error_count() == 0);
CHECK(mock.get_on_completed_count() == 1);
}
}
}
}

TEST_CASE("on_error_resume_next satisfies disposable contracts")
{
auto observable_disposable = rpp::composite_disposable_wrapper::make();
{
auto observable = observable_with_disposable<int>(observable_disposable);

test_operator_with_disposable<int>(
rpp::ops::on_error_resume_next([](const std::exception_ptr&) { return rpp::source::empty<int>(); }));
}

CHECK(observable_disposable.is_disposed() || observable_disposable.lock().use_count() == 2);
}

1 comment on commit 151959c

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BENCHMARK RESULTS (AUTOGENERATED)

ci-ubuntu-gcc

General

name rxcpp rpp prev rpp ratio
Subscribe empty callbacks to empty observable 302.48 ns 2.16 ns 2.16 ns 1.00
Subscribe empty callbacks to empty observable via pipe operator 303.05 ns 2.16 ns 2.16 ns 1.00

Sources

name rxcpp rpp prev rpp ratio
from array of 1 - create + subscribe + immediate 690.03 ns 0.31 ns 0.62 ns 0.50
from array of 1 - create + subscribe + current_thread 1029.86 ns 5.25 ns 5.25 ns 1.00
concat_as_source of just(1 immediate) create + subscribe 4020.41 ns 184.60 ns 121.85 ns 1.51
defer from array of 1 - defer + create + subscribe + immediate 1286.79 ns 0.63 ns 0.31 ns 2.03
interval - interval + take(3) + subscribe + immediate 3031.00 ns 61.93 ns 58.01 ns 1.07
interval - interval + take(3) + subscribe + current_thread 3342.33 ns 41.53 ns 32.11 ns 1.29

Filtering Operators

name rxcpp rpp prev rpp ratio
immediate_just+take(1)+subscribe 1067.97 ns 0.31 ns 0.31 ns 1.00
immediate_just+filter(true)+subscribe 836.34 ns 0.31 ns 0.32 ns 0.96
immediate_just(1,2)+skip(1)+subscribe 982.51 ns 0.34 ns 0.32 ns 1.08
immediate_just(1,1,2)+distinct_until_changed()+subscribe 880.07 ns 0.31 ns 0.32 ns 0.98
immediate_just(1,2)+first()+subscribe 1279.21 ns 0.62 ns 0.32 ns 1.94
immediate_just(1,2)+last()+subscribe 957.44 ns 0.31 ns 0.32 ns 0.98
immediate_just+take_last(1)+subscribe 1090.91 ns 17.59 ns 18.52 ns 0.95

Schedulers

name rxcpp rpp prev rpp ratio
immediate scheduler create worker + schedule 282.40 ns 2.92 ns 2.16 ns 1.35
current_thread scheduler create worker + schedule 370.25 ns 8.15 ns 7.41 ns 1.10
current_thread scheduler create worker + schedule + recursive schedule 814.45 ns 68.25 ns 65.58 ns 1.04

Transforming Operators

name rxcpp rpp prev rpp ratio
immediate_just+map(v*2)+subscribe 817.79 ns 0.31 ns 0.31 ns 1.00
immediate_just+scan(10, std::plus)+subscribe 885.00 ns 0.31 ns 0.31 ns 1.00
immediate_just+flat_map(immediate_just(v*2))+subscribe 2344.85 ns 153.71 ns 176.43 ns 0.87
immediate_just+buffer(2)+subscribe 1553.48 ns 13.89 ns 13.89 ns 1.00
immediate_just+window(2)+subscribe + subscsribe inner 2377.34 ns 1066.27 ns 1202.84 ns 0.89

Conditional Operators

name rxcpp rpp prev rpp ratio
immediate_just+take_while(false)+subscribe 824.61 ns - - 0.00
immediate_just+take_while(true)+subscribe 834.65 ns 0.31 ns 0.31 ns 1.00

Utility Operators

name rxcpp rpp prev rpp ratio
immediate_just(1)+subscribe_on(immediate)+subscribe 2254.24 ns 0.37 ns 0.32 ns 1.16

Combining Operators

name rxcpp rpp prev rpp ratio
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 3466.86 ns 177.62 ns 199.58 ns 0.89
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 3958.73 ns 189.10 ns 171.54 ns 1.10
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 136.30 ns 134.21 ns 1.02
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 3504.83 ns 1197.14 ns 966.65 ns 1.24
immediate_just(1) + zip(immediate_just(2)) + subscribe 2134.11 ns 213.22 ns 212.65 ns 1.00

Subjects

name rxcpp rpp prev rpp ratio
publish_subject with 1 observer - on_next 34.57 ns 11.71 ns 11.80 ns 0.99

Scenarios

name rxcpp rpp prev rpp ratio
basic sample 1375.83 ns 16.37 ns 16.66 ns 0.98
basic sample with immediate scheduler 1441.12 ns 5.56 ns 7.71 ns 0.72

Aggregating Operators

name rxcpp rpp prev rpp ratio
immediate_just+reduce(10, std::plus)+subscribe 907.96 ns 0.31 ns 0.31 ns 0.99

Error Handling Operators

name rxcpp rpp prev rpp ratio
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 1035.25 ns 136.36 ns - 0.00

ci-macos

General

name rxcpp rpp prev rpp ratio
Subscribe empty callbacks to empty observable 1008.45 ns 3.91 ns 3.98 ns 0.98
Subscribe empty callbacks to empty observable via pipe operator 984.84 ns 3.93 ns 3.86 ns 1.02

Sources

name rxcpp rpp prev rpp ratio
from array of 1 - create + subscribe + immediate 1935.91 ns 0.23 ns 0.23 ns 1.00
from array of 1 - create + subscribe + current_thread 2293.58 ns 25.26 ns 25.15 ns 1.00
concat_as_source of just(1 immediate) create + subscribe 5124.40 ns 305.69 ns 331.76 ns 0.92
defer from array of 1 - defer + create + subscribe + immediate 2490.09 ns 0.24 ns 0.23 ns 1.04
interval - interval + take(3) + subscribe + immediate 5603.02 ns 125.56 ns 114.71 ns 1.09
interval - interval + take(3) + subscribe + current_thread 6810.62 ns 121.03 ns 110.75 ns 1.09

Filtering Operators

name rxcpp rpp prev rpp ratio
immediate_just+take(1)+subscribe 2999.03 ns 0.27 ns 0.23 ns 1.15
immediate_just+filter(true)+subscribe 7030.79 ns 0.71 ns 0.23 ns 3.01
immediate_just(1,2)+skip(1)+subscribe 2800.17 ns 0.23 ns 0.23 ns 1.00
immediate_just(1,1,2)+distinct_until_changed()+subscribe 2377.63 ns 0.53 ns 0.47 ns 1.13
immediate_just(1,2)+first()+subscribe 3260.87 ns 1.09 ns 0.23 ns 4.66
immediate_just(1,2)+last()+subscribe 2386.80 ns 0.24 ns 0.24 ns 1.00
immediate_just+take_last(1)+subscribe 8853.98 ns 265.78 ns 68.97 ns 3.85

Schedulers

name rxcpp rpp prev rpp ratio
immediate scheduler create worker + schedule 983.82 ns 4.61 ns 4.07 ns 1.13
current_thread scheduler create worker + schedule 1189.21 ns 38.61 ns 36.38 ns 1.06
current_thread scheduler create worker + schedule + recursive schedule 2009.17 ns 219.84 ns 228.08 ns 0.96

Transforming Operators

name rxcpp rpp prev rpp ratio
immediate_just+map(v*2)+subscribe 2760.73 ns 0.26 ns 0.23 ns 1.10
immediate_just+scan(10, std::plus)+subscribe 2727.69 ns 0.54 ns 0.47 ns 1.15
immediate_just+flat_map(immediate_just(v*2))+subscribe 6116.95 ns 477.15 ns 416.36 ns 1.15
immediate_just+buffer(2)+subscribe 2926.24 ns 80.57 ns 69.12 ns 1.17
immediate_just+window(2)+subscribe + subscsribe inner 6101.36 ns 2596.27 ns 2314.40 ns 1.12

Conditional Operators

name rxcpp rpp prev rpp ratio
immediate_just+take_while(false)+subscribe 2399.49 ns - - 0.00
immediate_just+take_while(true)+subscribe 2345.71 ns 0.26 ns 0.23 ns 1.13

Utility Operators

name rxcpp rpp prev rpp ratio
immediate_just(1)+subscribe_on(immediate)+subscribe 5049.37 ns 0.25 ns 0.23 ns 1.09

Combining Operators

name rxcpp rpp prev rpp ratio
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 7644.12 ns 455.75 ns 455.27 ns 1.00
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 8451.04 ns 450.21 ns 451.55 ns 1.00
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 479.70 ns 478.95 ns 1.00
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 8823.23 ns 1913.16 ns 1958.72 ns 0.98
immediate_just(1) + zip(immediate_just(2)) + subscribe 5790.51 ns 959.65 ns 865.26 ns 1.11

Subjects

name rxcpp rpp prev rpp ratio
publish_subject with 1 observer - on_next 76.64 ns 49.33 ns 62.34 ns 0.79

Scenarios

name rxcpp rpp prev rpp ratio
basic sample 2763.84 ns 102.04 ns 107.65 ns 0.95
basic sample with immediate scheduler 2750.35 ns 14.19 ns 17.66 ns 0.80

Aggregating Operators

name rxcpp rpp prev rpp ratio
immediate_just+reduce(10, std::plus)+subscribe 2405.97 ns 0.23 ns 0.23 ns 1.00

Error Handling Operators

name rxcpp rpp prev rpp ratio
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 6722.93 ns 4138.35 ns - 0.00

ci-ubuntu-clang

General

name rxcpp rpp prev rpp ratio
Subscribe empty callbacks to empty observable 281.02 ns 0.88 ns 1.54 ns 0.57
Subscribe empty callbacks to empty observable via pipe operator 284.20 ns 0.88 ns 1.54 ns 0.57

Sources

name rxcpp rpp prev rpp ratio
from array of 1 - create + subscribe + immediate 677.17 ns 0.32 ns 0.31 ns 1.05
from array of 1 - create + subscribe + current_thread 873.86 ns 5.55 ns 5.56 ns 1.00
concat_as_source of just(1 immediate) create + subscribe 1998.37 ns 113.07 ns 112.64 ns 1.00
defer from array of 1 - defer + create + subscribe + immediate 607.39 ns 0.31 ns 0.31 ns 1.00
interval - interval + take(3) + subscribe + immediate 1534.42 ns 57.10 ns 57.09 ns 1.00
interval - interval + take(3) + subscribe + current_thread 2208.84 ns 30.88 ns 30.88 ns 1.00

Filtering Operators

name rxcpp rpp prev rpp ratio
immediate_just+take(1)+subscribe 969.58 ns 0.31 ns 0.31 ns 1.00
immediate_just+filter(true)+subscribe 670.02 ns 0.31 ns 0.31 ns 1.00
immediate_just(1,2)+skip(1)+subscribe 910.40 ns 0.31 ns 0.31 ns 1.00
immediate_just(1,1,2)+distinct_until_changed()+subscribe 695.40 ns 0.62 ns 0.62 ns 1.00
immediate_just(1,2)+first()+subscribe 1172.57 ns 0.31 ns 0.31 ns 1.00
immediate_just(1,2)+last()+subscribe 813.33 ns 0.31 ns 0.31 ns 1.00
immediate_just+take_last(1)+subscribe 969.56 ns 0.31 ns 0.31 ns 1.00

Schedulers

name rxcpp rpp prev rpp ratio
immediate scheduler create worker + schedule 200.20 ns 0.88 ns 1.54 ns 0.57
current_thread scheduler create worker + schedule 313.28 ns 5.89 ns 5.57 ns 1.06
current_thread scheduler create worker + schedule + recursive schedule 644.39 ns 59.23 ns 59.24 ns 1.00

Transforming Operators

name rxcpp rpp prev rpp ratio
immediate_just+map(v*2)+subscribe 671.97 ns 0.31 ns 0.31 ns 1.00
immediate_just+scan(10, std::plus)+subscribe 773.23 ns 0.31 ns 0.31 ns 1.00
immediate_just+flat_map(immediate_just(v*2))+subscribe 1895.69 ns 120.88 ns 119.57 ns 1.01
immediate_just+buffer(2)+subscribe 1429.17 ns 13.58 ns 13.59 ns 1.00
immediate_just+window(2)+subscribe + subscsribe inner 2266.86 ns 804.39 ns 821.11 ns 0.98

Conditional Operators

name rxcpp rpp prev rpp ratio
immediate_just+take_while(false)+subscribe 656.21 ns - - 0.00
immediate_just+take_while(true)+subscribe 685.71 ns 0.31 ns 0.31 ns 1.00

Utility Operators

name rxcpp rpp prev rpp ratio
immediate_just(1)+subscribe_on(immediate)+subscribe 1683.18 ns 0.31 ns 0.31 ns 1.00

Combining Operators

name rxcpp rpp prev rpp ratio
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 2641.89 ns 127.39 ns 124.74 ns 1.02
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 3109.48 ns 123.25 ns 121.56 ns 1.01
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 112.49 ns 114.38 ns 0.98
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 2712.24 ns 726.35 ns 732.53 ns 0.99
immediate_just(1) + zip(immediate_just(2)) + subscribe 1838.78 ns 174.05 ns 170.41 ns 1.02

Subjects

name rxcpp rpp prev rpp ratio
publish_subject with 1 observer - on_next 26.27 ns 14.18 ns 14.83 ns 0.96

Scenarios

name rxcpp rpp prev rpp ratio
basic sample 1060.64 ns 13.58 ns 13.28 ns 1.02
basic sample with immediate scheduler 1087.34 ns 5.87 ns 5.86 ns 1.00

Aggregating Operators

name rxcpp rpp prev rpp ratio
immediate_just+reduce(10, std::plus)+subscribe 811.26 ns 0.31 ns 0.31 ns 1.00

Error Handling Operators

name rxcpp rpp prev rpp ratio
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 885.50 ns 126.80 ns - 0.00

ci-windows

General

name rxcpp rpp prev rpp ratio
Subscribe empty callbacks to empty observable 587.06 ns 4.93 ns 4.01 ns 1.23
Subscribe empty callbacks to empty observable via pipe operator 595.56 ns 4.93 ns 4.01 ns 1.23

Sources

name rxcpp rpp prev rpp ratio
from array of 1 - create + subscribe + immediate 1185.43 ns 5.24 ns 5.24 ns 1.00
from array of 1 - create + subscribe + current_thread 1464.17 ns 19.19 ns 20.42 ns 0.94
concat_as_source of just(1 immediate) create + subscribe 4705.83 ns 168.19 ns 182.41 ns 0.92
defer from array of 1 - defer + create + subscribe + immediate 1221.40 ns 4.93 ns 5.24 ns 0.94
interval - interval + take(3) + subscribe + immediate 3104.55 ns 129.22 ns 130.65 ns 0.99
interval - interval + take(3) + subscribe + current_thread 3469.58 ns 59.52 ns 60.75 ns 0.98

Filtering Operators

name rxcpp rpp prev rpp ratio
immediate_just+take(1)+subscribe 1833.28 ns 12.85 ns 12.87 ns 1.00
immediate_just+filter(true)+subscribe 1714.04 ns 11.71 ns 12.37 ns 0.95
immediate_just(1,2)+skip(1)+subscribe 1811.72 ns 13.11 ns 13.01 ns 1.01
immediate_just(1,1,2)+distinct_until_changed()+subscribe 1625.34 ns 15.78 ns 15.94 ns 0.99
immediate_just(1,2)+first()+subscribe 2106.04 ns 12.64 ns 12.96 ns 0.98
immediate_just(1,2)+last()+subscribe 1486.85 ns 14.04 ns 14.13 ns 0.99
immediate_just+take_last(1)+subscribe 2040.35 ns 62.77 ns 61.51 ns 1.02

Schedulers

name rxcpp rpp prev rpp ratio
immediate scheduler create worker + schedule 492.90 ns 7.08 ns 7.34 ns 0.96
current_thread scheduler create worker + schedule 674.85 ns 17.59 ns 17.70 ns 0.99
current_thread scheduler create worker + schedule + recursive schedule 1121.11 ns 110.54 ns 112.46 ns 0.98

Transforming Operators

name rxcpp rpp prev rpp ratio
immediate_just+map(v*2)+subscribe 1334.77 ns 11.23 ns 12.25 ns 0.92
immediate_just+scan(10, std::plus)+subscribe 1439.17 ns 21.58 ns 21.58 ns 1.00
immediate_just+flat_map(immediate_just(v*2))+subscribe 3968.60 ns 232.66 ns 231.77 ns 1.00
immediate_just+buffer(2)+subscribe 2351.02 ns 57.80 ns 58.12 ns 0.99
immediate_just+window(2)+subscribe + subscsribe inner 4108.84 ns 1572.28 ns 1551.66 ns 1.01

Conditional Operators

name rxcpp rpp prev rpp ratio
immediate_just+take_while(false)+subscribe 1383.87 ns 11.45 ns 11.46 ns 1.00
immediate_just+take_while(true)+subscribe 1347.74 ns 11.69 ns 12.37 ns 0.95

Utility Operators

name rxcpp rpp prev rpp ratio
immediate_just(1)+subscribe_on(immediate)+subscribe 4320.75 ns 7.09 ns 7.71 ns 0.92

Combining Operators

name rxcpp rpp prev rpp ratio
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 5406.57 ns 229.80 ns 237.30 ns 0.97
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 6526.35 ns 227.79 ns 232.16 ns 0.98
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 235.98 ns 229.05 ns 1.03
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 6285.64 ns 965.19 ns 980.56 ns 0.98
immediate_just(1) + zip(immediate_just(2)) + subscribe 3929.00 ns 542.70 ns 541.84 ns 1.00

Subjects

name rxcpp rpp prev rpp ratio
publish_subject with 1 observer - on_next 36.39 ns 25.90 ns 26.59 ns 0.97

Scenarios

name rxcpp rpp prev rpp ratio
basic sample 1883.73 ns 59.85 ns 59.16 ns 1.01
basic sample with immediate scheduler 1876.69 ns 35.17 ns 39.17 ns 0.90

Aggregating Operators

name rxcpp rpp prev rpp ratio
immediate_just+reduce(10, std::plus)+subscribe 1462.22 ns 20.93 ns 19.96 ns 1.05

Error Handling Operators

name rxcpp rpp prev rpp ratio
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 1955.15 ns 345.50 ns - 0.00

Please sign in to comment.