A compact Functional/Reactive/Concurrent utility library on C++17.
A class template that provides function composition such as map and filter. Template parameter F
is used for inner structure, and normally you don't have to care about it. (Thanks to type or template parameter deducition.)
method | signature | description |
---|---|---|
<constructor> | () -> thunk<void> |
thunk{} constructs an empty thunk: thunk<void> . |
(const thunk<F> &)
| default;
| |
(thunk<F> &&)
| default;
| |
map | (G &/&&g) -> thunk<H> |
Return a new thunk that forward the invoke result of this thunk to a functor g . g must return something. (See then .) |
filter | (G &/&&g) -> thunk<H> |
Return a new thunk that immediately return std::nullopt if g(<invoke result of this thunk>) == false . Otherwise, the thunk return the result of this thunk. |
then | (G &/&&g) -> thunk<H> |
Return a new thunk, that call functor g by the invoke result of this thunk and then return the invoke result of this thunk. It's similar to map , but used to map side effect that returns void . |
try_map | (G &/&&g) -> thunk<H> |
g must return std::optional . Return a new thunk that immediately return std::nullopt if g(<invoke result of this thunk>) == std::nullopt . Otherwise, the thunk return the *g(<invoke result of this thunk>) . |
operator() | (T &/&&x) -> std::optional<R> |
Invoke the composed function by an argument x , then return the result wrapped in std::optional . (Because the result can be filtered and then be none.) |
Note: In this page, universal references are referred like as T &/&&
.
example:
auto is_even = [](auto n) { return n % 2 == 0; };
auto f = rat::thunk{}
.filter(is_even)
.then([](auto n) {
cout << "even: " << n << endl;
})
.map([](auto n) { return n / 2; })
.filter([](auto n) { return n > 5; });
f(10); // Print "even: 10", then return std::nullopt.
f(11); // Return std::nullopt.
f(12); // Print "even: 12", then return std::optional{6}.
A class template that bundle multiple functions. (thunk
combines functions in series, on the other hand, bundle
combines functions in parallel.)
method | signature | description |
---|---|---|
<constructor> | (Fs... fs) -> bundle<Fs...> |
Bundle multiple functions. |
(const bundle<Fs...> &)
| default;
| |
(bundle<Fs...> &&)
| default;
| |
bundle_with | (Gs &/&&... gs) -> bundle<Hs...> |
Return new bundle that is concatenated this bundle and functors gs... . If gs... contains some bundles, the bundles will be discomposed and rebundled. |
to_tuple | () -> std::tuple<Fs...> |
Convert this bundle to tuple. |
as_tuple | () & -> std::tuple<Fs...>& |
Get reference to this bundle as reference to tuple. |
() && -> std::tuple<Fs...>&& |
||
operator() | (Ts &/&&... xs) -> void |
Call each functions that this bundle contains one by one in order from top with arguments xs... . |
results_for | (Ts &/&&... xs) -> std::tuple<Rs...> |
Forward the result of invoking each functions by arguments xs... as tuple.There is no gurantee for invoke order. |
A class template that provides inter-thread communication. A channel can have multiple senders and only one receiver.
method | signature | description |
---|---|---|
get_receiver | () -> receiver<T> |
Get the receiver. If the receiver is already got, throw rat::concurrent::receiver_already_retrieved .If the channel is closed, throw rat::concurrent::channel_already_closed . |
get_sender | () -> sender<T> |
Get the sender. If the channel is closed, throw rat::concurrent::channel_already_closed . |
push | (const T &x) -> void |
Send a value to the channel then notify the receiver. |
(T &&x) -> void |
||
close | () -> void |
Close the channel then notify the receiver. |
You can get it by channel<T>::get_sender()
.
method | signature | description |
---|---|---|
push | (const T &x) -> void |
Send a value to the channel then notify the receiver. |
(T &&x) -> void |
||
close | () -> void |
Close the channel then notify the receiver. |
You can get it by channel<T>::get_receiver()
.
The receiver is non-copyable but moveable.
method | signature | description |
---|---|---|
next | () -> T |
Take the value sent to the channel one by one as same order as it was sent.If the channel is empty, block the thread until new value is sent.When the channel is closed, throw rat::concurrent::close_channel . |
share | () -> shared_receiver<T> |
Return shared_receiver and invalidate this receiver. |
The shared_receiver is a copyable receiver.Even if there are multiple shared_receiver, one sent value will received only one time on only one shared_receiver.It is useful for processing sent value on multiple threads.
method | signature | description |
---|---|---|
next | () -> T |
Take the value sent to the channel one by one as same order as it was sent.If the channel is empty, block the thread until new value is sent.When the channel is closed, throw rat::concurrent::close_channel . |
function | signature | description |
---|---|---|
make_channel<T> |
() -> std::pair<sender<T>, receiver<T>> |
Create a pair of sender<T> and receiver<T> . |
(with_shared_receiver_t) -> std::pair<sender<T>, shared_receiver<T>> |
When passed with_shared_receiver , share the receiver. |
example:
using namespace std::chrono_literals;
auto [sn, rc] = rat::make_channel<int>();
auto produce = [](auto sn) {
for (int i = 0; i < 10; ++i) {
sn.push(i);
std::this_thread::sleep_for(1s);
}
sn.close();
};
auto consume = [](auto rc) {
try {
while (true) {
std::cout << rc.next() << std::endl;
}
}
catch (const close_channel &) {
}
};
std::thread producer{produce, std::move(sn)};
std::thread consumer{consume, std::move(rc)};
producer.join();
consumer.join();