void
storage_t::drop_subscription_for_all_states(
	const mbox_t & mbox,
	const std::type_index & msg_type )
	{
		const is_same_mbox_msg is_same{ mbox->id(), msg_type };

		auto lower_bound = m_events.lower_bound(
				key_t{ mbox->id(), msg_type, nullptr } );

		auto need_erase = [&] {
				return lower_bound != std::end(m_events) &&
						is_same( lower_bound->first );
			};
		const bool events_found = need_erase();

		if( events_found )
			{
				do
					{
						m_events.erase( lower_bound++ );
					}
				while( need_erase() );

				// Note: since v.5.5.9 mbox unsubscription is initiated even if
				// it is MPSC mboxes. It is important for the case of message
				// delivery tracing.

				mbox->unsubscribe_event_handlers( msg_type, owner() );
			}
	}
void
storage_t::drop_subscription(
	const mbox_t & mbox,
	const std::type_index & msg_type,
	const state_t & target_state )
	{
		auto existed_position = find(
				m_events, mbox->id(), msg_type, target_state );
		if( existed_position != m_events.end() )
			{
				// Note v.5.5.9 unsubscribe_event_handlers is called for
				// mbox even if it is MPSC mbox. It is necessary for the case
				// of message delivery tracing.

				// We must destroy mbox subscription in case if the agent has no
				// more subscriptions for that mbox+msg_type pair.
				// Detect this while existed_position is not invalidated.
				bool must_unsubscribe_mbox =
						!is_known_mbox_msg_pair( m_events, existed_position );

				m_events.erase( existed_position );

				if( must_unsubscribe_mbox )
					{
						mbox->unsubscribe_event_handlers( msg_type, owner() );
					}
			}
	}
void
storage_t::drop_subscription_for_all_states(
	const mbox_t & mbox_ref,
	const std::type_index & type_index )
	{
		const key_t key( mbox_ref->id(), type_index );

		auto it = m_map.lower_bound( key );
		auto need_erase = [&] {
				return it != m_map.end() &&
						key.is_same_mbox_msg_pair( it->first );
			};
		const bool found = need_erase();
		if( found )
		{
			do
				{
					m_hash_table.erase( &(it->first) );
					m_map.erase( it++ );
				}
			while( need_erase() );

			mbox_ref->unsubscribe_event_handlers( type_index, owner() );
		}
	}
void
storage_t::create_event_subscription(
	const mbox_t & mbox,
	const std::type_index & msg_type,
	const message_limit::control_block_t * limit,
	const state_t & target_state,
	const event_handler_method_t & method,
	thread_safety_t thread_safety )
	{
		using namespace std;
		using namespace subscription_storage_common;

		const auto mbox_id = mbox->id();

		// Check that this subscription is new.
		auto existed_position = find(
				m_events, mbox_id, msg_type, target_state );

		if( existed_position != m_events.end() )
			SO_5_THROW_EXCEPTION(
				rc_evt_handler_already_provided,
				"agent is already subscribed to message, " +
				make_subscription_description( mbox, msg_type, target_state ) );

		// Just add subscription to the end.
		auto ins_result = m_events.emplace(
				subscr_map_t::value_type {
						key_t { mbox_id, msg_type, &target_state },
						value_t {
								mbox,
								event_handler_data_t { method, thread_safety }
						}
				} );

		// Note: since v.5.5.9 mbox subscription is initiated even if
		// it is MPSC mboxes. It is important for the case of message
		// delivery tracing.

		// If there was no subscription for that mbox
		// then new subscription in the mbox must be created.
		if( !is_known_mbox_msg_pair( m_events, ins_result.first ) )
			{
				so_5::details::do_with_rollback_on_exception(
					[&] {
						mbox->subscribe_event_handler(
								msg_type,
								limit,
								owner() );
					},
					[&] {
						m_events.erase( ins_result.first );
					} );
			}
	}