Giter Site home page Giter Site logo

victimsnino / reactiveplusplus Goto Github PK

View Code? Open in Web Editor NEW
204.0 8.0 18.0 99.27 MB

Implementation of async observable/observer (Reactive Programming) in C++ with care about performance and templates in mind in ReactiveX approach

Home Page: https://victimsnino.github.io/ReactivePlusPlus/v2/docs/html/md_docs_2readme.html

License: Boost Software License 1.0

CMake 2.46% C++ 97.07% Python 0.47%
cpp cpp20 rxcpp reactive-programming reactivex modern-cpp observable observer-pattern push-model rpp

reactiveplusplus's Introduction

ReactivePlusPlus

GitHub C++20 CI v2 Join the chat at https://gitter.im/ReactivePlusPlus/community Join the chat in Discord: https://discord.gg/KWMR3RNkVz

codecov Lines of Code Maintainability Rating GitHub commit activity (v2)

Usage:

ReactivePlusPlus is reactive programming library for C++20 language inspired by "official implementation" (RxCpp) and original idea (ReactiveX) that only depends on standard library and C++20 features (mostly on concepts).

See the BUILDING document to know how to build/install RPP. If you are going to know more details about developing for RPP check HACKING document.

Try out rpp on godbolt.org!

Documentation:

Check User Guide and API Reference of RPP.

Note about V2:

Currently I'm working on RPP v2 (v2 branch). RPP v2 follows "zero-overhead principle" and most of the operators are (and will) minimize overhead.

How? Due to elimination of heap allocations and avoiding unnecessary things. During implementatuon of v1 I've found a lot of cases where RPP does unnecessary expensive things. As a result, v2 does only required things and nothing else.

For example, v1's create+map+subscribe spends about 63.7768ns, while v2 is about 0.4ns.

v2 started from the scratch, so, each operator would be re-implemented from the scratch too. Implementation status can be tracked in #324

You still can use previous implementation. It placed in v1 branch

Overview:

In short: ReactivePlusPlus is library for building asynchronous event-driven streams of data with help of sequences of primitive operators in the declarative form.

Currently ReactivePlusPlus is still under development but it has a lot of implemented operators for now. List of implemented features can be found in API Reference with very detailed documentation for each of them.

Main advantages of ReactivePlusPlus are that it is written in Modern C++ with Performance and Usage in mind. v2 written to follow zero-overhead principle As a result it is fast, readable, easy to use and well-documented. And it is proven with continous benchmarking results of v2 and comparison with RxCpp

NOTE: ReactivePlusPlus is library for C++20. So, it works only on compilers that supports most C++20 features. List of minimal supported compilers:

  • (ubuntu) gcc-10
  • (ubuntu) clang-11
  • (windows) visual studio 2022
  • (macos) Apple Clang 14

Example:

rpp::source::from_callable(&::getchar)
   | rpp::operators::repeat()
   | rpp::operators::take_while([](char v) { return v != '0'; })
   | rpp::operators::filter(std::not_fn(&::isdigit))
   | rpp::operators::map(&::toupper)
   | rpp::operators::subscribe([](char v) { std::cout << v; });

There we are creating observable which emits value via invoking of getchar function, then repeats it infinite amount of time till termination event happes. It emits values while symbol is not equal to 0, takes only not digits, maps them to upper case and then just prints to console.

Also it supports QT out of box. Checkout RPPQT reference

Why do you need it?

Check the User Guide for a detailed overview of the Reactive Programming concept and RPP itself.

In short, RPP can help you build complex pipelines to distribute values over time, connect "some sources of data" without directly connecting them.

Take a look at the example code for QT. Here, you can see how to connect a button to a label and update it based on the number of clicks.

auto button          = new QPushButton("Click me!");
auto clicks_count_label = new QLabel();
QObject::connect(button, &QPushButton::clicked, [&clicks_count_label, count = 0]() mutable {
   clicks_count_label->setText(QString{"Clicked %1 times!"}.arg(++count));
});

In this example, the button is directly connected to the label. What if you want to link another widget to the same button?

auto button          = new QPushButton("Click me!");
auto clicks_count_label = new QLabel();
auto clicks_duration_label = new QLabel();
QObject::connect(button, &QPushButton::clicked, [&clicks_count_label, count = 0]() mutable {
   clicks_count_label->setText(QString{"Clicked %1 times!"}.arg(++count));
});
QObject::connect(button, &QPushButton::clicked, [&clicks_duration_label, now = std::chrono::high_resolution_clock::now()]() mutable {
   const auto old = std::exchange(now, std::chrono::high_resolution_clock::now());
   clicks_duration_label->setText(QString{"MS since last click %1!"}.arg(std::chrono::duration_cast<std::chrono::milliseconds>(now-old).count()));
});

Again directly connected... and it becomes a bit complex.. what if i want to accumulate two buttons at the same time? should i make a separate variable for this case? Build complex state to track it? Ideally it would be nice also to update "MS since last click %1!" at runtime each 1ms... So, looks like each label have to depend on multiple sources of data. It is not a trivial case. In this case it is nice opportunity to try RPP!

auto button_1              = new QPushButton("Click me!");
auto button_2              = new QPushButton("Click me!");
auto clicks_count_label    = new QLabel();
auto clicks_duration_label = new QLabel();

const auto clicks_1      = rppqt::source::from_signal(*button_1, &QPushButton::clicked);
const auto clicks_2      = rppqt::source::from_signal(*button_2, &QPushButton::clicked);
const auto merged_clicks = clicks_1 | rpp::operators::merge_with(clicks_2);

const auto total_clicks     = merged_clicks | rpp::operators::scan(0, [](int seed, auto) { return ++seed; });
const auto click_times      = merged_clicks | rpp::operators::map([](auto) { return std::chrono::high_resolution_clock::now(); });
const auto time_since_click = rpp::source::interval(std::chrono::milliseconds{1}, rppqt::schedulers::main_thread_scheduler{})
                              | rpp::operators::with_latest_from([](auto, const auto click_time) { return std::chrono::high_resolution_clock::now() - click_time; }, click_times);

// .....

total_clicks.subscribe([&clicks_count_label](int clicks)
{
   clicks_count_label->setText(QString{"Clicked %1 times in total!"}.arg(clicks));
});

time_since_click.subscribe([&clicks_duration_label](std::chrono::high_resolution_clock::duration ms) {
   clicks_duration_label->setText(QString{"MS since last click %1!"}.arg(std::chrono::duration_cast<std::chrono::milliseconds>(ms).count()));
});

Now we have separate observables for separate sources of dynamic data like clicks itself, clicks count and time of clicks. As a result, we can combine them in any way we want. At the same time now observables and actions for events can be separated easily - we have "some observable of some clicks or any counted event" and "some observable of durations". How this observables was obtained - doesn't matter. Also we easily built a much more complex pipeline without any difficulties.

What about existing Reactive Extension libraries for C++?

Reactive programming is excelent programming paradigm and approach for creation of multi-threading and real-time programs which reacts on some events. Unfortunately, there is only one stable and fully-implemented library at the moment of creation of ReactivePlusPlus - RxCpp.

RxCpp is great and awesome library and perfect implementation of ReactiveX approach. However RxCpp has some disadvantages:

  • It is a bit "old" library written in C++11 with some parts written in the pre-C++11 style (mess of old-style classes and wrappers)
  • Issue with template parameters: rxcpp::observable contains full chain of operators as second template parameter... where each operator has a bunch of another template parameters itself. It forces IDEs works slower while parsing resulting type of observable. Also it forces to generate heavier binaries and debug symbols and slower build time.
  • It has high perfomance cost due to tremendous amount of usage of heap.
  • Some parts of code written with non-effective logic

Another implementation of RX for c++: another-rxcpp. It partly solves issues of RxCpp via eliminating of template parameter with help of type-erasing and making each callback as std::function. As a result issue with templates resvoled, but this approach has disadvantages related to runtime: resulting size of observers/observables becomes greater due to heavy std::function object, usage of heap for storing everything causes perfomance issues, implementation is just pretty simple and provides a lot of copies of passed objects.

Why ReactivePlusPlus?

ReactivePlusPlus tries to solve all mentioned issues:

  • ReactivePlusPlus written in Modern C++ (C++20) with concepts which makes code-base a lot more understandable and clean:
    • Concepts provide more clear errors and checks: you will understand that pass something incorrect before compilation in IDE or during compilation with understandable errors instead of "invalid template class map_invalid_t"
    • Everywhere while possible used deduction of template arguments, for example, type of values of observable by type of subscriber used in on_subscribe and etc
  • ReactivePlusPlus keeps balance between performance and type-erasing mechanism
  • ReactivePlusPlus is fast: every part of code written with perfomance in mind. Starting from tests over amount of copies/move and finishing to Continous Benchmarking. Benchmarks prove that RPP faster than RxCPP in most cases: Continous benchmarking results and comparison with RxCpp

Useful links

Licensing

Boost Software License - Version 1.0 - August 17th, 2003

Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:

The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Credits:

ReactivePlusPlus library uses:

  • PVS-Studio - static analyzer for C, C++, C#, and Java code.
  • snitch for unit testing only, fetched automatically in case of RPP_BUILD_TESTS enabled
  • RxCpp only for comparison of performance between RPP and RxCpp in CI benchmarks. Used as cmake dependency under option
  • reactivex.io as source for insipration and definition of entities used in RPP. Some comments used in RPP source code taken from reactivex.io
  • rxmarbles python as generator of marbles graphs in doxygen documentation
  • cmake-init as generator for most part of initial CMakes

reactiveplusplus's People

Contributors

corentinbt avatar dependabot[bot] avatar gitter-badger avatar pre-commit-ci[bot] avatar tcw165 avatar thorstink avatar victimsnino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactiveplusplus's Issues

Rpp doesn't compile - VS22 - Windows - Latest release

Hi, I really need help. I've been trying to fix it for a long time.

I've been trying to compile ReactivePlusPlus, but for some reason it doesn't work.
Could you please help me to find a solution?

I did as described BUILDING.md and it didn't work.
I'll show below the erros I found and what I did to create my project.

These are the errors messages when I try to build on Visual Studio 2022 version 4.8.04161:

Severity	Code	Description	Project	File	Line	Suppression State
Error	C3539	a template-argument cannot be a type that contains 'auto'	DemoRPP	D:\cpp\DemoRPP\DemoRPP\rpp\observers\specific_observer.hpp	81	
Error	C3539	a template-argument cannot be a type that contains 'auto'	DemoRPP	D:\cpp\DemoRPP\DemoRPP\rpp\observers\specific_observer.hpp	87	
Error	C3539	a template-argument cannot be a type that contains 'auto'	DemoRPP	D:\cpp\DemoRPP\DemoRPP\rpp\observers\specific_observer.hpp	94	
Error	C3539	a template-argument cannot be a type that contains 'auto'	DemoRPP	D:\cpp\DemoRPP\DemoRPP\rpp\observers\specific_observer.hpp	101	
Error	C2672	'rpp::details::member_overload<Type,SpecificObservable,rpp::details::subscribe_tag>::subscribe_impl': no matching overloaded function found	DemoRPP	D:\cpp\DemoRPP\DemoRPP\rpp\operators\fwd\subscribe.hpp	60	
Error	C2672	'make_specific_subscriber': no matching overloaded function found	DemoRPP	D:\cpp\DemoRPP\DemoRPP\rpp\operators\fwd\subscribe.hpp	60	

This is how I created my project:

(1) Empty C++ project on VS22 > Created main.cpp file ( https://pastebin.com/raw/qMBkwkiM )
main.cpp screenshot: https://ibb.co/fpPbKP6

(2) After that, I changed it to C++20 and later to C++ latest
C++20 project screenshot: https://ibb.co/q9FRGGV

(3) I downloaded the latest release and I added it to my project. rpp_release
Added RPP screenshot: https://ibb.co/3mPkdBk

How I added to my project: Properties > C/C++ > Additional Include Directories.

  • I can see that VS recognizes the folders and the lib - I can navigate inside the functions/methods definitions.
  • I tried different paths when I added it to my project.
  • I tried build x64 - Release and Debug mode

What should I do to fix it?

Thanks in advance

EDIT: VS22 preview is the issue here

Polish early_unsubscribe

early_unsubscribe feature works awesome, but we can also extend it via adding checks to callbacks if someone requested unsubscribe or not

Question about sample_with_time (oversampling)

Hi There,
i have a question regarding the sample_with_time operator. When reading the documentation and running the example, it gets clear, that this operator can serve for undersampling:

            source observable              : +--1---2-3-4---5-6-7-|
            operator "sample_with_time(2)" : +--1---2---4---5---7-|

However, it does not seem to work with oversampling, e.g.:

            source observable              : +--1-----3-4---5-6-7-|
            operator "sample_with_time(2)" : +--1---1---4---5---7-|

I know this behaviour from rxJava and i worked around this using a time-based buffer.
I cannot tell, if that behaviour is really intended.

Anyway, i could have a usage for some time based operators, if oversampling will not work here. (e.g. buffer with time).

What do you think?

Provide in-place manipulation of stateful subjects (behaviour subject)

Hey there,
I have another feature request for you :)
I was wondering, if one could manipulate the state of a behaviour subject in-place?
Imagine, if subject carries complex object, e.g.
publish_subject<std::map<std::string, std::pair<double, double>>>.
Instead of changing the whole map instance, it would be more efficient to change the map in-place and emit manually.
What is your opinion on that?

The trampoline scheduler in rpp seems slower than in rxcpp

We've found that trampoline scheduler works a bit slower than rxcpp on ubuntu. We need to find source of this issue.

Also subscribe started to work slower after introduction of trampoline scheduler. It's unexpected to have such a huge performance hit.

Re-implement scheduler's related code

UPD:

  1. Split TrampolineScheduler into two:
    1. TrampolineScheduler which JUST TRAMPOLINE with LOCAL queue to just schedule "schedulable after current schedulable completed"
    2. CurrentThreadScheduler = TrampolineScheduler with thread_local queues
  2. Re-implement scheduler's based operators in the following way:
    1. Instead of "just scheduling" each emission to scheduler it needs to have local queue
    2. On new emission push emission to queue
    3. If queue is empty, then schedule draining of queue to scheduler
    4. If queue is not empty, then just do nothing due to "someone else" just scheduled draining
    5. Recursively re-schedule same schedulable to drain queue while queue is not empty.
  3. (????) NewThread/RunLoop and etc should store their queues as "CurrentThread" or not?

Create another v1 release

Hi there,
great to watch your effort on v2!

However, I am still using v1 since I am using operators and other stuff which is not completed yet for v2.
For v1 I also need a recent version, which I obtain via CMake's fetchcontent and a commit hash. This has same drawbacks, since it takes a lot of time to check out. A better way would be to rely on a tag/release. So, are you planning to create another (or last) release for the v1 branch?
That would be great :)

Thanks already.

Fails to compile with clang11

README claims that clang11 is supported, but when I try the basic example with clang11 on Linux, compilation fails:

In file included from /home/conan/w/prod/BuildSingleReference/conan-center-index/recipes/reactiveplusplus/all/test_package/test_package.cpp:1:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/rpp.hpp:13:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/observables.hpp:19:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/observables/specific_observable.hpp:14:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/observables/fwd.hpp:13:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/subscribers/fwd.hpp:13:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/observers/constraints.hpp:13:
In file included from /home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/observers/fwd.hpp:13:
/home/conan/w/prod/BuildSingleReference/.conan/data/reactiveplusplus/0.1.2/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/rpp/utils/constraints.hpp:13:10: fatal error: 'concepts' file not found
#include <concepts>

Could you provide exact minimum supported versions of major compilers please (gcc, clang, msvc, apple-clang, though I guess apple-clang is not supported at all since it fails to compile even with latest version apple-clang 14 due to lack of std::ranges support)?

Reemit from subscription

Hi there,
another question regarding some detail about your lib (still on v1, though).
Apparently, there is some issue when emitting something from within a subscription.

The following won't work:

publish_subject<int> subject1;
publish_subject<int> subject2;
subject1.subscribe([](int value) {
  subject2.get_subscriber().on_next(value+1); // This will block
});

However, this will do the trick:

publish_subject<int> subject1;
publish_subject<int> subject2;
subject1.subscribe(subject2.get_subscriber());

Due to a complex operation, I would prefer something with the first syntax. (Instead of using the map operator or similar).
Can you give me a hint here, please?

Thanks already! :)

How to refer to observable type anyway?

It's a common practice to return an observable<T> to for a method to represent values of T in async fashion.

class Person {
   observable<std::string> Talk();
} 

While rpp does provide an observable class, but it has too many class template arguments which I can find very few explainations in docs. Before reading your whole project code, would you please enlighten me about a simple way to define actual class type other than auto.

Re-implement scheduler's related code

  • (???) Split TrampolineScheduler into two:
    1. TrampolineScheduler which JUST TRAMPOLINE with LOCAL queue to just schedule "schedulable after current schedulable completed"
    2. CurrentThreadScheduler = TrampolineScheduler with thread_local queues
  • Re-implement scheduler's based operators in the following way:
    1. Instead of "just scheduling" each emission to scheduler it needs to have local queue
    2. On new emission push emission to queue
    3. If queue is empty, then schedule draining of queue to scheduler
    4. If queue is not empty, then just do nothing due to "someone else" just scheduled draining
    5. Recursively re-schedule same schedulable to drain queue while queue is not empty.
  • (????) NewThread/RunLoop and etc should store their queues as "CurrentThread" or not?

New issue like replacement for #277

Run loop scheduler

Hi, thanks for creating this great project that keep the reactive programming up!

I wonder whether there is an implementation or plan to implement the runloop scheduler as in the rxcpp library? I found it effective to implement the cooperative multiprocessing an embedded platform.

Thanks!

Resolve "nano sleeps"

Currently we are doing sleep_for inside schedulers. BUT sleeping is pretty expensive operation, so, if we are doing sleep_for(std::chrono::nanoseconds{1}) actually it is about 18-50k nanoseconds sleep. So, actually sleep with duration <= 18-50k ns is unreachable with std.

UPD: Looks like clang/gcc uses nanosleep and it doesn't work
UPD: Looks like best possible solution: change RPP's granularity to microseconds instead

Group-by test fails in debug mode

Discussed in #194

All the tests passed, except for test_group_by.exe. It threw an exception for invalid comparator at this line of the test;

obs.group_by(std::identity{}, std::identity{}, [](int, int){return true;}).subscribe([&](const auto& grouped)

which ultimately called this line and the emplace that crashed:

auto [itr, inserted] = state->key_to_subject.try_emplace(key);

The STL source code indicates that this fails because

 // test if _Pred(_Left, _Right) and _Pred is strict weak ordering, when the arguments are the cv-same-type
STL Excerpt
template <class _Pr, class _Ty1, class _Ty2,
    enable_if_t<is_same_v<_Remove_cvref_t<_Ty1>, _Remove_cvref_t<_Ty2>>, int> = 0>
constexpr bool _Debug_lt_pred(_Pr&& _Pred, _Ty1&& _Left, _Ty2&& _Right) noexcept(
    noexcept(_Pred(_Left, _Right)) && noexcept(_Pred(_Right, _Left))) {
    // test if _Pred(_Left, _Right) and _Pred is strict weak ordering, when the arguments are the cv-same-type
    const auto _Result = static_cast<bool>(_Pred(_Left, _Right));
    if (_Result) {
        _STL_VERIFY(!_Pred(_Right, _Left), "invalid comparator");
    }

    return _Result;
}

That's as far as I've gone on drilling down into the problem. I just wanted to give you a heads up.

Add average operator (and other statistical)

Hi @victimsnino
i am opening another thread, since it might exceed my original request(s) a bit...

How open are you about non-(rx)-standard filters?

The average operator is already part of the original rx definition (which i also have a usage for).
However, other filters come to my mind like exponential moving average or median filtering. Those are realised in influxdb:
https://docs.influxdata.com/flux/v0.x/stdlib/universe/exponentialmovingaverage/
https://docs.influxdata.com/flux/v0.x/stdlib/universe/median/

I don't know, whether there are implementations for other languages, but those filters would be pretty helpful for financial, statistical and signal processing applications (and for my application...).

Looking forward to your opinion on that.

libuv / uvw integration

Hi @victimsnino,

i would like to come up with another request :)
As already mentioned before i replaced Qt with libuv (or specifically uvw, libuv's C++ wrapper).
Do you plan any further mainloop integrations (besides Qt)?

That would be great. Thanks a lot!

segfault in snake

Built examples with

cmake -B build -DRPP_BUILD_SAMPLES=1 -DCMAKE_CXX_COMPILER=clang++-14 -DRPP_BUILD_SFML_CODE=1 -DRPP_BUILD_TESTS=1 -DCMAKE_BUILD_TYPE=Debug

cmake --build build

tests all passed.

but running build/bin/snake pops up the sfml window and then immediately segfaults.

ubuntu 20.04 with clang14 and SFML 2.5.1 (from system apt repo)

gdb ./build/bin/snake

run

Program received signal SIGSEGV, Segmentation fault.
0x000055555558d719 in move_snake (body=..., direction_and_length=std::tuple containing = {...}) at /home/oliver/c/ReactivePlusPlus/src/samples/sfml/snake/snake.cpp:28
28	    auto head = body.back();

the backtrace is quite overwhelming

Consider pushing builds to NUGet

NUGet does not require libraries to be of at least 1.0 versioning, and pushing development versions gives you more exposure. This in turn increases your feedback.

Two broken links

Hi,

first, many thanks for this amazing library, which makes reactive finally usable in c++.

Please fix two broken links:

Thx.

creating an observable from C callback functions

I cannot figure out the correct way to create an observable from a C style emitter with callback functions. Example shape:

typedef void (*StringCallback)(const char* s);
typedef void (*DoneCallback)();
// we don't know how this function is implemented, only that it calls onstring()
// a number of times and ondone() once, almost certainly from another thread.
void do_async_thing(StringCallback onstring, DoneCallback ondone);

I have a solution of sorts, but it is almost certainly "wrong" as it involves creating a dynamic object and cleaning up. Rather than lead with my incorrect approach, better to just ask flatly how to turn the above into an observable to which I can subscribe. The key point in the setup above is that all the "state" is maintained inside the black box which is do_async_thing(). It takes care of whatever state it needs to emit C strings, I don't. I am sure the solution is "obvious" once I see it, but I've tried at length and appear to be missing something fundamental. TIA.

Throttle operator

Hi there,
great to watch your progress with v2 and I already saw, that you are about to integrate Qt again.
I would have another request for an operator: this time it is "throttle".

Once Qt and throttle is there, I will switch to RppV2 and serve as tester :)

Thanks again and best regards!

Please update RPP in conan center

As my current project relies heavily on conan, and coincidentally I am using distinct op in v2.1.0 as git submodule, please conisder updading package in conan.

At the time being, latest version on conan is still v2.0.0. And I've requested update request at conan center.

Let me know if anything I can do to speed up the process.

Game example(s)

Given the asynchronous nature of Rx and the performant aspect of this library makes it a possible candidate for rapid prototyping of games which are just transforming a stream of user interactions to a stream of graphics.

There is an example of Reactive programming used in a very elegant way, just composing together all the parts in a single statement, but it is in Scala.

There was also interest in this style of programming, at Microsoft in the 90s, for animation and multimedia of which the aforementioned Scala library is an example (still need to read the paper, which has examples in Haskel).

If Rx is as suitable as I think for games, it would be an awesome tool for game jams once a library of reusable components was built up. Starting with SDL2, I think, would make a good start and I'd be keen to help out there where I can.

(I confess I only recently started trying to write simple 2D games in order learn C++, albeit I have 20+ years as a software engineer and I've been itching to find an application of Rx I could get into)

macOS/clang support

Hey there,
thanks for this nice lib.
I am trying to compile it on macOS with its shipped clang. Unfortunately, this is not working, since some c++20 features are missing within clang and libc++: std::ranges::for_each, std::ranges::copy_if, std::stop_token.
https://en.cppreference.com/w/cpp/compiler_support/20#C.2B.2B14_library_features

My question is, will you consider compatibility with macOS and clang?
If yes, are there any plans on this in the near future?
Or would you accept PRs fixing macOS/clang compilation?

Thanks a lot!

timeout operator

The timeout operator can be very useful to implement when deal with the communication protocols. However, not all languages implemented this operator. Is there any plan to implement it in this library or is there some alternative with the existing operators?

Thanks!

QT support

Add support for QT as rppqt:

  1. Create sources to create observable from signal
  2. Create scheduler to schedule emissions to "main" thread
  3. Create some examples

RPP v2 - Implementation Status

Current implementation is really good and fast BUT it does a lot of unnecessary heap allocations AND a lot of unnecessary moves/copies while it is not needed. Need to change architecture to eliminate unnecessary copies/moves

  1. use rvalue while possible
  2. subscription -> disposable. Not observer owns subscription and tracks ITS correctness, but observable provides disposable and tracks observable's correctness
  3. observer is not copyable at all
  4. Make RPP v2 as ZERO OVERHEAD library

Implementation status

Fundamentals

  • Observables
    • Specific Observable (was in v1)
    • Dynamic Observable (was in v1)
    • Blocking Observable (was in v1)
    • Connectable Observable (was in v1)
  • Observers
    • Specific Observer (was in v1)
    • Dynamic Observer (was in v1)
  • Disposables
    • Base Disposable
    • Callback Disposable (was in v1)
    • Composite Disposable (was in v1)
    • RefCount Disposable
  • Schedulers
    • Immediate (was in v1)
    • New Thread (was in v1)
    • CurrentThread (was in v1)
    • RunLoop (was in v1)
    • EventLoop

Creating Observables

  • Create (was in v1)
  • Just (was in v1)
    • + memory_model (was in v1)
  • empty/never/error
  • from
    • iterable (was in v1)
    • future
    • callable (was in v1)
    • async
  • defer
  • interval
  • range
  • repeat
  • timer
  • concat

Operators

Transforming

  • map (was in v1)
  • group_by (was in v1)
  • flat_map (was in v1)
  • scan
    • scan with initial seed (was in v1)
    • scan without seed
  • buffer
    • count (was in v1)
      • skip
    • time
    • time_or_count
  • window
    • count (was in v1)
      • skip
    • time
    • time_or_count
    • toggle

Filtering

  • filter (was in v1)
  • take (was in v1)
  • debounce (was in v1)
  • distinct
    • distinct
    • distinct_until_changed (was in v1)
  • element_at
  • first (was in v1)
  • ignore_elements
  • last (was in v1)
  • sample (was in v1)
    • sample (observable)
    • sample_with_time
  • skip (was in v1)
  • skip_last
  • take_last (was in v1)
  • throttle

Conditional

  • take_while (was in v1)
  • all
  • amb
  • contains
  • default_if_empty
  • sequence_equal
  • skip_until
  • skip_while
  • take_until (was in v1)

Combining

  • merge
    • observable of observables (was in v1)
    • merge with (was in v1)
    • merge delay error
  • switch
    • switch_map (was in v1)
    • switch_on_next (was in v1)
    • switch_if_empty
  • with_latest_from (was in v1)
  • start_with (was in v1)
  • combine_latest (was in v1)
  • zip

Aggregate

  • average
  • concat (was in v1)
  • count
  • max
  • min
  • reduce (was in v1)
  • sum

Backpressure

  • backpressure ???

Error handling

  • on_error_resume (was in v1)
  • retry

Utility

  • observe_on (was in v1)
  • repeat (was in v1)
    • scheduling (by default trampoline ?)
  • subscribe_on (was in v1)
  • delay (was in v1)
  • do/tap (was in v1)
    • tap with observer
    • tap with callbacks
    • do_on_next
    • do_on_error
    • do_on_completed
  • timeout (was in v1)
    • timeout
    • timeout with fallback observable
  • finally

Connectable

  • publish (was in v1)
  • multicast (was in v1)
  • connect (was in v1)
  • ref_count (was in v1)
  • replay

Subjects

  • publish_subject (was in v1)
  • behavior_subject (was in v1)
  • serialized_subject
  • replay_subject
  • async_subject

QT:

  • from_event (was in v1)
  • main_thread_scheduler (was in v1)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.