v.5.8.1 - Stiffstream/sobjectizer GitHub Wiki
This page describes changes and new features of v.5.8.1.
- A new message sink implementation
- New methods so_5::agent_t::so_this_agent_disp_binder() and so_5::agent_t::so_this_coop_disp_binder()
- A fix for limit_then_transform and mutable messages
The v.5.8.1 provides a ready-to use implementation of a message sink that transforms and redirects a message/signal.
The easiest way to use this functionality is to use the so_5::bind_transformer
helper function:
so_5::multi_sink_binding_t binding; // Can't use single_sink_binding_t here because
// binding object will hold several bindings.
so_5::bind_transformer(binding, source_mbox,
// Type of the incoming message will be deduced from a lambda parameter.
[dest_mbox](const source_msg_type & msg) {
return so_5::make_transformed<result_msg_type>(dest_mbox,
... /* some values from msg */ );
});
// Type of the source message is specified explicitly.
// This is required for mutable messages and signals.
so_5::bind_transformer< so_5::mutable_msg<source_msg_type> >(binding, source_mbox,
[dest_mbox](source_msg_type & msg) // Note the use of non-const reference, it is
// allowed here because the message is mutable.
{
return so_5::make_transformed<result_msg_type>(dest_mbox,
... /* some values from msg */ );
});
so_5::bind_transformer< source_signal_type >(binding, source_mbox,
[dest_mbox]() // Note that transformer lambda without a parameter has to
// be used for signals.
{
return so_5::make_transformed<result_signal_type>(dest_mbox);
});
The so_5::bind_transformer
allows to specify an optional delivery filter (note that a delivery filter can only be specified for messages, not signals):
so_5::bind_transformer< so_5::mutable_msg<source_msg_type> >(binding, source_mbox,
// The transformer.
[dest_mbox](source_msg_type & msg) // Note the use of non-const reference, it is
// allowed here because the message is mutable.
{
return so_5::make_transformed<result_msg_type>(dest_mbox,
... /* some values from msg */ );
},
// The delivery filter. The delivery filter will be called first and only
// if the delivery filter return `true` the transformer will be invoked.
[](const auto & msg) // Note the use of const-reference.
// Delivery filters always receive const-references,
// even for mutable messages.
{
return ... /* some condition that uses the content of the `msg` */;
});
There is a new example bind_transformer
in the sample
folder that shows the use of so_5::bind_transformer
function.
Under the hood the so_5::bind_transformer
uses so_5::msinks::transform_then_redirect
factory function(s). The so_5::msinks::transform_then_redirect
is also a new feature of v.5.8.1. It can be used by a user if simple so_5::bind_transformer
is not enough.
New methods so_5::agent_t::so_this_agent_disp_binder() and so_5::agent_t::so_this_coop_disp_binder()
Two new methods of so_5::agent_t
class simplify creation of a child coop with binding agents from it to the dispatcher already used for the parent agent (or for the cooperation of the parent agent).
For example, for so_this_agent_disp_binder
:
class parent_agent final : public so_5::agent_t
{
void create_new_child_coop() {
so_5::introduce_child_coop(*this,
// Use the parent agent dispatcher as the default dispatcher
// for agents from a new coop.
so_this_agent_disp_binder(),
[this](so_5::coop_t & coop) {
... /* Creation of agents */
});
}
...
};
...
// Registration of the coop with the parent agent.
env.introduce_coop(
// Use active_obj dispatcher as the default for this coop.
so_5::disp::active_obj::make_dispatcher(env).binder(),
[](so_5::coop_t & coop) {
// The parent agent will use the active_obj dispatcher by default.
coop.make_agent<parent_agent>(...);
... /* Creation of other agents. */
});
In that case agents from a child coop will use the same active_obj
dispatcher as the parent agent.
Sometimes it's necessary to distinguish the dispatcher for the parent agent and for the parent coop. In that case so_this_coop_disp_binder
will help:
class parent_agent final : public so_5::agent_t
{
void create_new_child_coop() {
so_5::introduce_child_coop(*this,
// Use the parent coop dispatcher as the default dispatcher
// for agents from a new coop.
so_this_coop_disp_binder(),
[this](so_5::coop_t & coop) {
... /* Creation of agents */
});
}
...
};
...
// Registration of the coop with the parent agent.
env.introduce_coop(
// Use thread_pool dispatcher as the default for this coop.
so_5::disp::thread_pool::make_dispatcher(env, 9u).binder(),
[](so_5::coop_t & coop) {
// The parent agent will use a separate one_thread dispatcher.
coop.make_agent_with_binder<parent_agent>(
so_5::disp::one_thread::make_dispatcher(env).binder(),
...);
... /* Creation of other agents. */
});
In that case agents from a child coop will be bound to a thread_pool
dispatcher, not to one_thread
dispatcher used for the parent agent.
Up to v.5.8.1 there was a flaw in the SObjectizer implementation: the limit_then_transform
overload reaction could not be used with mutable messages. This problem is fixed in v.5.8.1, not it is possible to write like this:
some_agent::some_agent(context_t ctx)
: so_5::agent_t{ ctx + limit_then_transform< so_5::mutable_msg< my_msg > >(
[this](my_msg & msg) /* Note the use of non-const reference */ {
return so_5::make_transformed< another_msg >(...);
})
}
{...}
The specificator so_5::immutable_msg<M>
is also supported now for limit_then_transform
:
some_agent::some_agent(context_t ctx)
: so_5::agent_t{ ctx + limit_then_transform< so_5::immutable_msg< my_msg > >(
[this](const my_msg & msg) /* Note the use of const reference */ {
return so_5::make_transformed< another_msg >(...);
})
}
{...}
Support for so_5::immutable_msg<M>
and so_5::mutable_msg<M>
is important for case when agent is a template:
template<typename Src_Msg>
class some_message_handler final : public so_5::agent_t {
public:
some_message_handler(context_t ctx)
: so_5::agent_t{ctx
+ limit_then_transform<Src_Msg>([this](const auto & msg) {...})
+ ... /* other limits */
}
{...}
};
...
coop.make_agent< some_message_handler< so_5::immutable_msg<received_data> > >(...);
coop.make_agent< some_message_handler< so_5::mutable_msg<parsed_data> > >(...);