2
3
6
7
8
9
10
11
13#include <so_5/impl/subscription_storage_iface.hpp>
17#include <unordered_map>
20#include <so_5/details/rollback_on_exception.hpp>
29
30
31
32
33
58 std::type_index msg_type )
67 std::type_index msg_type,
81 if( m_msg_type < o.m_msg_type )
83 else if( m_msg_type == o.m_msg_type )
93 return m_mbox_id == o.m_mbox_id &&
94 m_msg_type == o.m_msg_type &&
101 return m_mbox_id == o.m_mbox_id &&
102 m_msg_type == o.m_msg_type;
110
111
112
113
114
126 std::hash< so_5::mbox_id_t >()( ptr->m_mbox_id );
128 (std::hash< std::type_index >()( ptr->m_msg_type ) +
129 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
131 return h2 ^ (std::hash<
const state_t * >()(
133 0x9e3779b9 + (h2 << 6) + (h2 >> 2));
141
142
143
144
145
163 typename S::iterator it )
165 if( it != s.begin() )
167 typename S::iterator prev = it;
169 if( it->first.is_same_mbox_msg_pair( prev->first ) )
173 typename S::iterator next = it;
175 if( next != s.end() )
176 return it->first.is_same_mbox_msg_pair( next->first );
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
215 const mbox_t & mbox_ref,
216 const std::type_index & type_index,
219 const event_handler_method_t & method,
225 const mbox_t & mbox_ref,
226 const std::type_index & type_index,
227 const state_t & target_state )
noexcept override;
231 const mbox_t & mbox_ref,
232 const std::type_index & type_index )
noexcept override;
240 const std::type_index & msg_type,
241 const state_t & current_state )
const noexcept override;
244 debug_dump( std::ostream & to )
const override;
254 subscription_storage_common::subscr_info_vector_t && info )
override;
273
274
275
276
304 const std::type_index & type_index,
307 const event_handler_method_t & method,
313 key_t key{ mbox->id(), type_index, target_state };
315 auto insertion_result = m_map.emplace(
317 mbox_with_sink_info_t{ mbox, std::ref(message_sink) } );
319 if( !insertion_result.second )
321 rc_evt_handler_already_provided,
322 "agent is already subscribed to message, " +
323 make_subscription_description( mbox, type_index, target_state ) );
327 m_hash_table.emplace( &(insertion_result.first->first),
328 event_handler_data_t( method, thread_safety, handler_kind ) );
330 [&] { m_map.erase( insertion_result.first ); } );
332 auto mbox_msg_known = is_known_mbox_msg_pair(
333 m_map, insertion_result.first );
334 if( !mbox_msg_known )
339 mbox->subscribe_event_handler(
340 type_index, message_sink );
343 m_hash_table.erase( &(insertion_result.first->first) );
344 m_map.erase( insertion_result.first );
351 const mbox_t & mbox_ref,
352 const std::type_index & type_index,
353 const state_t & target_state )
noexcept
355 key_t key( mbox_ref->id(), type_index, target_state );
357 auto it = m_map.find( key );
359 if( m_map.end() != it )
361 bool mbox_msg_known = is_known_mbox_msg_pair( m_map, it );
367 m_hash_table.erase( &(it->first) );
370 if( !mbox_msg_known )
372 mbox_ref->unsubscribe_event_handler( type_index, sink );
379 const mbox_t & mbox_ref,
380 const std::type_index & type_index )
noexcept
382 const key_t key( mbox_ref->id(), type_index );
384 auto it = m_map.lower_bound( key );
385 auto need_erase = [&] {
386 return it != m_map.end() &&
387 key.is_same_mbox_msg_pair( it->first );
389 const bool found = need_erase();
399 m_hash_table.erase( &(it->first) );
402 while( need_erase() );
404 mbox_ref->unsubscribe_event_handler( type_index, sink );
417 const std::type_index & msg_type,
418 const state_t & current_state )
const noexcept
420 key_t k( mbox_id, msg_type, current_state );
421 auto it = m_hash_table.find( &k );
422 if( it != m_hash_table.end() )
423 return &(it->second);
431 for(
const auto & v : m_map )
432 to <<
"{" << v.first.m_mbox_id <<
", "
433 << v.first.m_msg_type.name() <<
", "
434 << v.first.m_state->query_name() <<
"}"
442 const map_t::value_type * previous =
nullptr;
443 for(
auto & i : m_map )
449 !previous->first.is_same_mbox_msg_pair( i.first ) )
451 i.second.m_mbox->unsubscribe_event_handler(
453 i.second.m_message_sink.get() );
466 m_hash_table.clear();
477 subscr_info_vector_t events;
479 if( !m_hash_table.empty() )
481 events.reserve( m_hash_table.size() );
483 transform( begin(m_hash_table), end(m_hash_table),
484 back_inserter(events),
485 [
this](
const hash_table_t::value_type & i )
487 auto map_item = m_map.find( *(i.first) );
489 return subscr_info_t {
490 map_item->second.m_mbox,
491 map_item->first.m_msg_type,
492 map_item->second.m_message_sink.get(),
493 *(map_item->first.m_state),
495 i.second.m_thread_safety,
506 subscription_storage_common::subscr_info_vector_t && info )
512 hash_table_t fresh_table;
514 for_each( begin(info), end(info),
515 [&](
const subscr_info_t & i )
517 key_t k{ i.m_mbox->id(), i.m_msg_type, *(i.m_state) };
519 auto ins_result = fresh_map.emplace(
521 mbox_with_sink_info_t{
526 fresh_table.emplace( &(ins_result.first->first), i.m_handler );
529 swap( m_map, fresh_map );
530 swap( m_hash_table, fresh_table );
536 return m_hash_table.size();
547 return impl::subscription_storage_unique_ptr_t(
548 new impl::hash_table_subscr_storage::storage_t() );
Interface for message sink.
A storage for agent's subscriptions information.
void drop_subscription_for_all_states(const mbox_t &mbox_ref, const std::type_index &type_index) noexcept override
hash_table_t m_hash_table
Hash table of event handlers.
void setup_content(subscription_storage_common::subscr_info_vector_t &&info) override
Setup content from information from another storage object.
void drop_content() noexcept override
Drop all content.
virtual void create_event_subscription(const mbox_t &mbox_ref, const std::type_index &type_index, abstract_message_sink_t &message_sink, const state_t &target_state, const event_handler_method_t &method, thread_safety_t thread_safety, event_handler_kind_t handler_kind) override
const event_handler_data_t * find_handler(mbox_id_t mbox_id, const std::type_index &msg_type, const state_t ¤t_state) const noexcept override
void destroy_all_subscriptions() noexcept
void debug_dump(std::ostream &to) const override
virtual void drop_subscription(const mbox_t &mbox_ref, const std::type_index &type_index, const state_t &target_state) noexcept override
std::size_t query_subscriptions_count() const override
Count of subscriptions in the storage.
map_t m_map
Map of subscriptions.
subscription_storage_common::subscr_info_vector_t query_content() const override
void drop_all_subscriptions() noexcept override
Drop all subscriptions.
An interface of subscription storage.
std::enable_if< details::is_agent_method_pointer< details::method_arity::nullary, Method_Pointer >::value, state_t & >::type on_enter(Method_Pointer pfn)
Set on enter handler.
#define SO_5_THROW_EXCEPTION(error_code, desc)
Some reusable and low-level classes/functions which can be used in public header files.
bool is_known_mbox_msg_pair(S &s, typename S::iterator it)
A hash_table-based storage for agent's subscriptions information.
Common stuff for various subscription storage implementations.
Details of SObjectizer run-time implementations.
Private part of message limit implementation.
thread_safety_t
Thread safety indicator.
SO_5_FUNC subscription_storage_factory_t hash_table_based_subscription_storage_factory()
Factory for default subscription storage based on std::unordered_map.
mbox_id_t null_mbox_id()
Default value for null mbox_id.
event_handler_kind_t
Kind of an event handler.
Information about event_handler and its properties.
A special class for checking equality via pointer to key.
bool operator()(const key_t *a, const key_t *b) const
A special class for calculating hash value via pointer to key.
std::size_t operator()(const key_t *ptr) const noexcept
key_t(mbox_id_t mbox_id, std::type_index msg_type, const state_t &state)
Initializing constructor.
std::type_index m_msg_type
Message type.
bool is_same_mbox_msg_pair(const key_t &o) const noexcept
mbox_id_t m_mbox_id
Unique ID of mbox.
const state_t * m_state
State of agent.
bool operator==(const key_t &o) const noexcept
key_t()
Default constructor.
bool operator<(const key_t &o) const noexcept
key_t(mbox_id_t mbox_id, std::type_index msg_type)
std::reference_wrapper< abstract_message_sink_t > m_message_sink