state_t::state_t( agent_t * target_agent, std::string state_name, state_t * parent_state, std::size_t nested_level, history_t state_history ) : m_target_agent{ target_agent } , m_state_name( std::move(state_name) ) , m_parent_state{ parent_state } , m_initial_substate{ nullptr } , m_state_history{ state_history } , m_last_active_substate{ nullptr } , m_nested_level{ nested_level } , m_substate_count{ 0 } { if( parent_state ) { // We should check the deep of nested states. if( m_nested_level >= max_deep ) SO_5_THROW_EXCEPTION( rc_state_nesting_is_too_deep, "max nesting deep for agent states is " + std::to_string( max_deep ) ); // Now we can safely mark parent state as composite. parent_state->m_substate_count += 1; } }
void agent_t::so_change_state( const state_t & new_state ) { ensure_operation_is_on_working_thread( "so_change_state" ); if( new_state.is_target( this ) ) { auto actual_new_state = new_state.actual_state_to_enter(); if( !( *actual_new_state == *m_current_state_ptr ) ) { // New state differs from the current one. // Actual state switch must be performed. do_state_switch( *actual_new_state ); // State listener should be informed. m_state_listener_controller->changed( *this, *m_current_state_ptr ); } } else SO_5_THROW_EXCEPTION( rc_agent_unknown_state, "unable to switch agent to alien state " "(the state that doesn't belong to this agent)" ); }
state_t & state_t::time_limit( duration_t timeout, const state_t & state_to_switch ) { if( duration_t::zero() == timeout ) SO_5_THROW_EXCEPTION( rc_invalid_time_limit_for_state, "zero can't be used as time limit for state '" + query_name() ); // Old time limit must be dropped if it exists. drop_time_limit(); m_time_limit.reset( new time_limit_t{ timeout, state_to_switch } ); // If this state is active then new time limit must be activated. if( is_active() ) so_5::details::do_with_rollback_on_exception( [&] { m_time_limit->set_up_limit_for_agent( *m_target_agent, *this ); }, [&] { // Time limit must be dropped because it is not activated // for the current state. drop_time_limit(); } ); return *this; }
void ensure_queue_not_full( Q && queue ) { if( queue.is_full() ) SO_5_THROW_EXCEPTION( rc_msg_chain_is_full, "an attempt to push a message to full demand queue" ); }
void ensure_queue_not_empty( Q && queue ) { if( queue.is_empty() ) SO_5_THROW_EXCEPTION( rc_msg_chain_is_empty, "an attempt to get message from empty demand queue" ); }
void abstract_message_chain_t::remove_from_select( mchain_props::select_case_t & /*select_case*/ ) { SO_5_THROW_EXCEPTION( rc_not_implemented, "abstract_message_chain_t::remove_from_select(select_case) is " "not implemented in abstract_message_chain_t class" ); }
mchain_props::extraction_status_t abstract_message_chain_t::extract( mchain_props::demand_t & /*dest*/, mchain_props::select_case_t & /*select_case*/ ) { SO_5_THROW_EXCEPTION( rc_not_implemented, "abstract_message_chain_t::extract(demand,select_case) is " "not implemented in abstract_message_chain_t class" ); // Just to make compilers happy. return mchain_props::extraction_status_t::no_messages; }
state_t::state_t( initial_substate_of parent, std::string state_name, history_t state_history ) : state_t{ parent.m_parent_state->m_target_agent, std::move(state_name), parent.m_parent_state, parent.m_parent_state->m_nested_level + 1, state_history } { if( m_parent_state->m_initial_substate ) SO_5_THROW_EXCEPTION( rc_initial_substate_already_defined, "initial substate for state " + m_parent_state->query_name() + " is already defined: " + m_parent_state->m_initial_substate->query_name() ); m_parent_state->m_initial_substate = this; }
const state_t * state_t::actual_state_to_enter() const { const state_t * s = this; while( 0 != s->m_substate_count ) { if( s->m_last_active_substate ) // Note: for states with shallow history m_last_active_substate // can point to composite substate. This substate must be // processed usual way with checking for substate count, presence // of initial substate and so on... s = s->m_last_active_substate; else if( !s->m_initial_substate ) SO_5_THROW_EXCEPTION( rc_no_initial_substate, "there is no initial substate for composite state: " + query_name() ); else s = s->m_initial_substate; } return s; }