SObjectizer  5.5
Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
so_5::subscription_bind_t Class Reference

A class for creating a subscription to messages from the mbox. More...

#include <agent.hpp>

Public Member Functions

 subscription_bind_t (agent_t &agent, const mbox_t &mbox_ref)
 
subscription_bind_tin (const state_t &state)
 Set up a state in which events are allowed be processed. More...
 
template<typename Method_Pointer >
std::enable_if< details::is_agent_method_pointer< Method_Pointer >::value, subscription_bind_t &>::type event (Method_Pointer pfn, thread_safety_t thread_safety=not_thread_safe)
 Make subscription to the message. More...
 
template<typename Message , typename Method_Pointer >
std::enable_if< details::is_agent_method_pointer< Method_Pointer >::value, subscription_bind_t &>::type event (signal_indicator_t< Message >(), Method_Pointer pfn, thread_safety_t thread_safety=not_thread_safe)
 Make subscription to the signal. More...
 
template<class Lambda >
std::enable_if< details::lambda_traits::is_lambda< Lambda >::value, subscription_bind_t &>::type event (Lambda &&lambda, thread_safety_t thread_safety=not_thread_safe)
 Make subscription to the message by lambda-function. More...
 
template<class Message , class Lambda >
std::enable_if< details::lambda_traits::is_lambda< Lambda >::value, subscription_bind_t &>::type event (signal_indicator_t< Message >(), Lambda &&lambda, thread_safety_t thread_safety=not_thread_safe)
 Make subscription to the signal by lambda-function. More...
 
template<typename Signal , typename... Args>
subscription_bind_tevent (Args &&... args)
 Make subscription to the signal. More...
 
template<typename Msg >
subscription_bind_ttransfer_to_state (const state_t &target_state)
 An instruction for switching agent to the specified state and transfering event proceessing to new state. More...
 
template<typename Msg >
subscription_bind_tsuppress ()
 Suppress processing of event in this state. More...
 
template<typename Msg >
subscription_bind_tjust_switch_to (const state_t &target_state)
 Define handler which only switches agent to the specified state. More...
 
template<class Message , class Lambda>
std::enable_if< details::lambda_traits::is_lambda< Lambda >::value, subscription_bind_t &>::type event (signal_indicator_t< Message >(*)(), Lambda &&lambda, thread_safety_t thread_safety)
 

Private Types

typedef std::vector< const state_t *> state_vector_t
 Type of vector of states. More...
 

Private Member Functions

void create_subscription_for_states (const std::type_index &msg_type, const event_handler_method_t &method, thread_safety_t thread_safety) const
 Create subscription of event for all states. More...
 
void ensure_handler_can_be_used_with_mbox (const so_5::details::msg_type_and_handler_pair_t &handler) const
 Additional check for subscription to a mutable message from MPMC mbox. More...
 

Private Attributes

agent_tm_agent
 Agent to which we are subscribing. More...
 
mbox_t m_mbox_ref
 Mbox for messages to subscribe. More...
 
state_vector_t m_states
 States of agents the event to be subscribed in. More...
 

Detailed Description

A class for creating a subscription to messages from the mbox.

This type provides one of the ways to subscribe an agent's event handlers. There are two way to do that. The first one uses so_5::state_t::event() methods:

class subscribe_demo : public so_5::agent_t
{
// Some states for the agent.
state_t st_first{this}, st_second{this}, st_third{this};
...
virtual void so_define_agent() override {
// Subscribe just one event handler for st_first.
st_first.event(some_mbox, &subscribe_demo::event_handler_1);
// Subscribe two event handlers for st_second.
st_second
.event(some_mbox, &subscribe_demo::event_handler_1)
.event(some_mbox, &subscribe_demo::event_handler_2);
// Subscribe two event handlers for st_third.
st_third
.event(some_mbox, &subscribe_demo::event_handler_1)
.event(some_mbox, &subscribe_demo::event_handler_3)
}
};

But this way do not allow to subscribe the same event handler for several states in the compact way.

This can be done via agent_t::so_subscribe(), agent_t::so_subscribe_self() and subscription_bind_t object:

class subscribe_demo : public so_5::agent_t
{
// Some states for the agent.
state_t st_first{this}, st_second{this}, st_third{this};
...
virtual void so_define_agent() override {
// Subscribe event_handler_1 for all three states
so_subscribe(some_mbox)
.in(st_first)
.in(st_second)
.in(st_third)
.event(&subscribe_demo::event_handler_1);
// Subscribe just one event handler for st_second and st_third.
so_subscribe(some_mbox)
.in(st_second)
.event(&subscribe_demo::event_handler_2);
// Subscribe two event handlers for st_third.
so_subscribe(some_mbox)
.in(st_third)
.event(&subscribe_demo::event_handler_3)
}
};
Some words about binder logic...
An object of type subscription_bind_t collects list of states enumerated by calls to subscription_bind_t::in() method. Every call to in() method add a state to that list. It means:
so_subscribe(some_mbox) // list is: {}
.in(st_first) // list is: {st_first}
.in(st_second) // list is: {st_first, st_second}
.in(st_third) // list is: {st_first, st_second, st_third}
...
A call to event() or suppress() or just_switch_to() applies subscription to all states which are currently in the list. But these calls do not remove the content of that list. It means:
so_subscribe(some_mbox) // list is: {}
.in(st_first) // list is: {st_first}
.event(handler_1) // subscribe for state st_first only.
.in(st_second) // list is: {st_first, st_second}
.event(handler_2) // subscribe for state st_first and for st_second.
.in(st_third) // list is: {st_first, st_second, st_third}
.event(handler_3) // subscribe for state st_first, st_second and st_third.
...

Member Typedef Documentation

◆ state_vector_t

typedef std::vector< const state_t * > so_5::subscription_bind_t::state_vector_t
private

Type of vector of states.

Since
v.5.3.0

Constructor & Destructor Documentation

◆ subscription_bind_t()

so_5::subscription_bind_t::subscription_bind_t ( agent_t agent,
const mbox_t mbox_ref 
)
inline
Parameters
agentAgent to subscribe.
mbox_refMbox for messages to be subscribed.

Member Function Documentation

◆ create_subscription_for_states()

void so_5::subscription_bind_t::create_subscription_for_states ( const std::type_index &  msg_type,
const event_handler_method_t method,
thread_safety_t  thread_safety 
) const
inlineprivate

Create subscription of event for all states.

Since
v.5.3.0

◆ ensure_handler_can_be_used_with_mbox()

void so_5::subscription_bind_t::ensure_handler_can_be_used_with_mbox ( const so_5::details::msg_type_and_handler_pair_t handler) const
inlineprivate

Additional check for subscription to a mutable message from MPMC mbox.

Such attempt must be disabled because delivery of mutable messages via MPMC mboxes is prohibited.

Exceptions
so_5::exception_tif m_mbox_ref is a MPMC mbox and handler is for mutable message.
Since
v.5.5.19

◆ event() [1/6]

template<typename Method_Pointer >
std::enable_if< details::is_agent_method_pointer< Method_Pointer >::value, subscription_bind_t &>::type so_5::subscription_bind_t::event ( Method_Pointer  pfn,
thread_safety_t  thread_safety = not_thread_safe 
)

Make subscription to the message.

Since
v.5.5.14
Note
Can be used for message and signal handlers.
Usage example
struct engine_control : public so_5::message_t { ... };
struct check_status : public so_5::signal_t {};
class engine_controller : public so_5::agent_t
{
public :
virtual void so_define_agent() override
{
so_subscribe_self()
.event( &engine_controller::control )
.event( &engine_controller::check_status );
.event( &engine_controller::accelerate );
...
}
...
private :
void control( so_5::mhood_t< engine_control > & cmd ) { ... }
void check_status( so_5::mhood_t< check_status > & cmd ) { ... }
void accelerate( so_5::mhood_t< int > & cmd ) { ... }
};
Parameters
pfnEvent handling method.
thread_safetyThread safety of the event handler.
Examples:
so_5/adv_thread_pool_fifo/main.cpp, so_5/custom_error_logger/main.cpp, so_5/deadletter_handler/main.cpp, so_5/hardwork_imit/main.cpp, so_5/hello_evt_handler/main.cpp, so_5/hello_evt_lambda/main.cpp, so_5/machine_control/main.cpp, so_5/many_timers/main.cpp, so_5/modify_resend_as_immutable/main.cpp, so_5/mutable_msg_agents/main.cpp, so_5/parent_coop/main.cpp, so_5/ping_pong_minimal/main.cpp, so_5/prio_work_stealing/main.cpp, so_5/producer_consumer_mchain/main.cpp, so_5/selective_msg_tracing/main.cpp, so_5/stop_guard/main.cpp, so_5/svc/parallel_sum/main.cpp, so_5/two_handlers/main.cpp, and so_5/wrapped_env_demo/main.cpp.

◆ event() [2/6]

template<typename Message , typename Method_Pointer >
std::enable_if< details::is_agent_method_pointer< Method_Pointer >::value, subscription_bind_t &>::type so_5::subscription_bind_t::event ( signal_indicator_t< Message >  (),
Method_Pointer  pfn,
thread_safety_t  thread_safety = not_thread_safe 
)

Make subscription to the signal.

Since
v.5.3.0
Note
This method supports event-methods for signals only.
Usage example
struct turn_on : public so_5::signal_t {};
struct turn_off : public so_5::signal_t {};
class engine_controller : public so_5::agent_t
{
public :
virtual void so_define_agent() override
{
so_subscribe_self()
.event( so_5::signal< turn_on >, &engine_controller::evt_turn_on )
.event( so_5::signal< turn_off >, &engine_controller::evt_turn_off );
...
}
...
private :
void evt_turn_on() { ... }
void evt_turn_off() { ... }
};
Attention
There is a more convient form of event() for subscription of signal handlers:
so_subscribe_self().event< turn_on >( &engine_controller::evt_turn_on );
Deprecated:
Will be removed in v.5.6.0.
Parameters
pfnEvent handling method.
thread_safetyThread safety of the event handler.

◆ event() [3/6]

template<typename Lambda >
std::enable_if< details::lambda_traits::is_lambda< Lambda >::value, subscription_bind_t &>::type so_5::subscription_bind_t::event ( Lambda &&  lambda,
thread_safety_t  thread_safety = not_thread_safe 
)

Make subscription to the message by lambda-function.

Since
v.5.3.0
Attention
Only lambda-function in the forms:
Result (const Message &)
Result (Message)
Result (const so_5::mhood_t<Message> &)
are supported.
Usage example.
enum class engine_control { turn_on, turn_off, slow_down };
struct setup_params : public so_5::message_t { ... };
struct update_settings { ... };
class engine_controller : public so_5::agent_t
{
public :
virtual void so_define_agent() override
{
so_subscribe_self()
.event( [this]( engine_control evt ) {...} )
.event( [this]( const setup_params & evt ) {...} )
.event( [this]( const update_settings & evt ) {...} )
...
}
...
};
Parameters
lambdaEvent handler code.
thread_safetyThread safety of the event handler.

◆ event() [4/6]

template<class Message , class Lambda >
std::enable_if< details::lambda_traits::is_lambda<Lambda>::value, subscription_bind_t & >::type so_5::subscription_bind_t::event ( signal_indicator_t< Message >  (),
Lambda &&  lambda,
thread_safety_t  thread_safety = not_thread_safe 
)

Make subscription to the signal by lambda-function.

Since
v.5.3.0
Attention
Only lambda-function in the form:
Result ()
is supported.
Note
This method supports event-lambdas for signals only.
Usage example
struct turn_on : public so_5::signal_t {};
struct turn_off : public so_5::signal_t {};
class engine_controller : public so_5::agent_t
{
public :
virtual void so_define_agent() override
{
so_subscribe_self()
.event( so_5::signal< turn_on >, [this]{ ... } )
.event( so_5::signal< turn_off >, [this]{ ... } );
...
}
...
};
Attention
There is a more convient form of event() for subscription of signal handlers:
so_subscribe_self().event< turn_on >( [this]{...} );
Deprecated:
Will be removed in v.5.6.0.
Parameters
lambdaEvent handling lambda.
thread_safetyThread safety of the event handler.

◆ event() [5/6]

template<typename Signal , typename... Args>
subscription_bind_t& so_5::subscription_bind_t::event ( Args &&...  args)
inline

Make subscription to the signal.

Since
v.5.5.1
Usage sample:
virtual void my_agent::so_define_agent()
{
so_subscribe_self().event< msg_my_signal >( &my_agent::event );
so_subscribe_self().event< msg_another_signal >( [=] { ... } );
}

◆ event() [6/6]

template<class Message , class Lambda>
std::enable_if< details::lambda_traits::is_lambda<Lambda>::value, subscription_bind_t & >::type so_5::subscription_bind_t::event ( signal_indicator_t< Message >  *)(,
Lambda &&  lambda,
thread_safety_t  thread_safety 
)

◆ in()

subscription_bind_t & so_5::subscription_bind_t::in ( const state_t state)
inline

Set up a state in which events are allowed be processed.

Parameters
stateState in which events are allowed.

◆ just_switch_to()

template<typename Msg >
subscription_bind_t & so_5::subscription_bind_t::just_switch_to ( const state_t target_state)

Define handler which only switches agent to the specified state.

Since
v.5.5.15
Note
This method differes from transfer_to_state() method: just_switch_to() changes state of the agent, but there will not be a look for event handler for message/signal in the new state. It means that just_switch_to() is just a shorthand for:
virtual void demo::so_define_agent() override
{
so_subscribe_self().in( S1 )
.event< some_signal >( [this]{ this >>= S2; } );
}
With just_switch_to() this code can looks like:
virtual void demo::so_define_agent() override
{
so_subscribe_self().in( S1 )
.just_switch_to< some_signal >( S2 );
}

◆ suppress()

template<typename Msg >
subscription_bind_t & so_5::subscription_bind_t::suppress ( )

Suppress processing of event in this state.

Since
v.5.5.15
Note
This method is useful because the event is not passed to event handlers from parent states. For example:
class demo : public so_5::agent_t
{
state_t S1{ this, "1" };
state_t S2{ initial_substate_of{ S1 }, "2" };
state_t S3{ initial_substate_of{ S2 }, "3" };
public :
virtual void so_define_agent() override
{
so_subscribe_self().in( S1 )
// Default event handler which will be inherited by states S2 and S3.
.event< msg1 >(...)
.event< msg2 >(...)
.event< msg3 >(...);
so_subscribe_self().in( S2 )
// A special handler for msg1.
// For msg2 and msg3 event handlers from state S1 will be used.
.event< msg1 >(...);
so_subscribe_self().in( S3 )
// Message msg1 will be suppressed. It will be simply ignored.
// No events from states S1 and S2 will be called.
.suppress< msg1 >()
// The same for msg2.
.suppress< msg2 >()
// A special handler for msg3. Overrides handler from state S1.
.event< msg3 >(...);
}
};

◆ transfer_to_state()

template<typename Msg >
subscription_bind_t & so_5::subscription_bind_t::transfer_to_state ( const state_t target_state)

An instruction for switching agent to the specified state and transfering event proceessing to new state.

Since
v.5.5.15
Usage example:
class device : public so_5::agent_t {
state_t off{ this, "off" };
state_t on{ this, "on" };
public :
virtual void so_define_agent() override {
so_subscribe_self().in( off )
.transfer_to_state< key_on >( on )
.transfer_to_state< key_info >( on );
}
...
};
Note
Event will not be postponed or returned to event queue. A search for a handler for this event will be performed immediately after switching to the new state.
New state can use transfer_to_state for that event too:
class device : public so_5::agent_t {
state_t off{ this, "off" };
state_t on{ this, "on" };
state_t status_dialog{ this, "status" };
public :
virtual void so_define_agent() override {
so_subscribe_self().in( off )
.transfer_to_state< key_on >( on )
.transfer_to_state< key_info >( on );
so_subscribe_self().in( on )
.transfer_to_state< key_info >( status_dialog )
...;
}
...
};
Since v.5.5.22.1 actual execution of transfer_to_state operation can raise so_5::exception_t with so_5::rc_transfer_to_state_loop error code if a loop in transfer_to_state is detected.

Member Data Documentation

◆ m_agent

agent_t* so_5::subscription_bind_t::m_agent
private

Agent to which we are subscribing.

◆ m_mbox_ref

mbox_t so_5::subscription_bind_t::m_mbox_ref
private

Mbox for messages to subscribe.

◆ m_states

state_vector_t so_5::subscription_bind_t::m_states
private

States of agents the event to be subscribed in.

Since
v.5.3.0

The documentation for this class was generated from the following file: