1 /* 2 * SObjectizer-5 3 */ 4 5 /*! 6 * \since 7 * v.5.5.5 8 * 9 * \file 10 * \brief Definition of storage for delivery filters. 11 */ 12 13 #pragma once 14 15 #include <so_5/mbox.hpp> 16 17 #include <so_5/compiler_features.hpp> 18 19 #include <so_5/details/rollback_on_exception.hpp> 20 21 #include <map> 22 23 namespace so_5 { 24 25 namespace impl { 26 27 // 28 // delivery_filter_storage_t 29 // 30 /*! 31 * \since 32 * v.5.5.5 33 * 34 * \brief Storage for message delivery filters. 35 * 36 * \attention This storage do not drop filters in the destructor. 37 * It is because the reference to agent is necessary for filter dropping. 38 * Storage do not have this reference. 39 * Because of that it is necessary to drop all filters explicitely 40 * by drop_all() method. 41 */ 42 class delivery_filter_storage_t 43 { 44 //! Type of key for filters map. 45 struct key_t 46 { 47 //! Message mbox. 48 mbox_t m_mbox; 49 //! Message type. 50 std::type_index m_msg_type; 51 52 bool operator <so_5::impl::delivery_filter_storage_t::key_t53 operator<( const key_t & o ) const 54 { 55 const abstract_message_box_t & a = *m_mbox; 56 const abstract_message_box_t & b = *(o.m_mbox); 57 return a < b || ( a == b && m_msg_type < o.m_msg_type ); 58 } 59 }; 60 61 //! Type of filters map. 62 using map_t = std::map< key_t, delivery_filter_unique_ptr_t >; 63 64 //! Information about defined filters. 65 map_t m_filters; 66 67 public : 68 //! Drop all defined filters. 69 /*! 70 * Filters are removed from corresponding mboxes and destroyed. 71 */ 72 void drop_all(agent_t & owner)73 drop_all( agent_t & owner ) noexcept 74 { 75 for( auto & p : m_filters ) 76 p.first.m_mbox->drop_delivery_filter( 77 p.first.m_msg_type, 78 owner ); 79 80 m_filters.clear(); 81 } 82 83 //! Set a delivery filter. 84 /*! 85 * If there already is previous filter it will be destroyed. 86 */ 87 void set_delivery_filter(const mbox_t & mbox,const std::type_index & msg_type,delivery_filter_unique_ptr_t filter,agent_t & owner)88 set_delivery_filter( 89 const mbox_t & mbox, 90 const std::type_index & msg_type, 91 delivery_filter_unique_ptr_t filter, 92 agent_t & owner ) 93 { 94 const key_t key{ mbox, msg_type }; 95 auto it = m_filters.find( key ); 96 if( it == m_filters.end() ) 97 { 98 // There is no previous filter. 99 // New filter must be added. 100 auto ins_result = m_filters.emplace( 101 map_t::value_type{ key, std::move( filter ) } ); 102 so_5::details::do_with_rollback_on_exception( 103 [&] { 104 mbox->set_delivery_filter( 105 msg_type, 106 *(ins_result.first->second), 107 owner ); 108 }, 109 [&] { 110 m_filters.erase( ins_result.first ); 111 } ); 112 } 113 else 114 { 115 // Replace previous filter with new one. 116 delivery_filter_unique_ptr_t old{ std::move( it->second ) }; 117 it->second = std::move( filter ); 118 119 // Mbox must change delivery filter too. 120 so_5::details::do_with_rollback_on_exception( 121 [&] { 122 mbox->set_delivery_filter( 123 msg_type, 124 *(it->second), 125 owner ); 126 }, 127 [&] { 128 it->second = std::move( old ); 129 } ); 130 } 131 } 132 133 //! Remove delivery filter. 134 void drop_delivery_filter(const mbox_t & mbox,const std::type_index & msg_type,agent_t & owner)135 drop_delivery_filter( 136 const mbox_t & mbox, 137 const std::type_index & msg_type, 138 agent_t & owner ) noexcept 139 { 140 auto it = m_filters.find( key_t{ mbox, msg_type } ); 141 if( it != m_filters.end() ) 142 { 143 mbox->drop_delivery_filter( msg_type, owner ); 144 m_filters.erase( it ); 145 } 146 } 147 }; 148 149 } /* namespace impl */ 150 151 } /* namespace so_5 */ 152 153