SObjectizer-5 Extra
Loading...
Searching...
No Matches
pub.hpp
Go to the documentation of this file.
1/*!
2 * @file
3 * @brief Support for hierarchy of message types.
4 *
5 * @since v.1.6.2
6 */
7
8#pragma once
9
10#include <so_5/version.hpp>
11
12#if SO_5_VERSION < SO_5_VERSION_MAKE(5u, 8u, 0u)
13#error "SObjectizer-5.8.0 of newest is required"
14#endif
15
16#include <so_5_extra/error_ranges.hpp>
17
18#include <so_5/unique_subscribers_mbox.hpp>
19#include <so_5/environment.hpp>
20
21#include <cstdint>
22#include <iostream>
23#include <memory>
24#include <shared_mutex>
25#include <type_traits>
26
28{
29
30namespace errors
31{
32
33/*!
34 * @brief An attempt to get parent upcaster but it isn't exists.
35 *
36 * @since v.1.6.2
37 */
40
41/*!
42 * @brief An attempt to deliver signal via msg_hierarchy-related mbox.
43 *
44 * msg_hierarchy and signals are incompatible.
45 *
46 * @since v.1.6.2
47 */
50
51/*!
52 * @brief An attempt to deliver a message that type is not derived from root.
53 *
54 * @since v.1.6.2
55 */
58
59/*!
60 * @brief An attempt to create receiving mbox for a mutable message.
61 *
62 * @since v.1.6.2
63 */
66
67/*!
68 * @brief There are more than one subscriber for a mutable message.
69 *
70 * A demuxer can't deliver an instance of a mutable message if there are
71 * more than one subscriber for this message.
72 *
73 * @since v.1.6.2
74 */
77
78} /* namespace errors */
79
80namespace impl
81{
82
84
85//
86// upcaster_factory_t
87//
88/*!
89 * @brief Type of pointer to factory function for making upcaster object.
90 */
91using upcaster_factory_t =
92 message_upcaster_t (*)(::so_5::message_mutability_t) noexcept;
93
94//
95// message_upcaster_t
96//
97/*!
98 * @brief Upcaster for a message.
99 *
100 * It's simple object that holds a type_index for message type for that
101 * this object has been created.
102 *
103 * It also may holds a pointer to parent's type upcaster factory. This pointer
104 * will be nullptr if the current type if a root of the hierarchy.
105 */
107 {
108 //! Type of the message for that this upcaster has been created.
110
111 //! Pointer to parent's type upcaster factory.
112 //!
113 //! Will be nullptr, if there is no parent type and self_type is
114 //! the root of the hierarchy.
115 upcaster_factory_t m_parent_factory;
116
117 public:
118 //! Initializing constructor.
120 //! Type for that this upcaster object has been created.
121 std::type_index self_type,
122 //! Pointer to parent's type upcaster factory or nullptr.
123 upcaster_factory_t parent_factory )
125 , m_parent_factory{ parent_factory }
126 {}
127
128 //! Getter of the type for that this upcaster object has been created.
129 [[nodiscard]] const std::type_index &
130 self_type() const noexcept
131 {
132 return m_self_type;
133 }
134
135 //! Does parent's type factory exists?
136 //!
137 //! @retval true if parent's type factory present and parent_upcaster() can
138 //! be safely called.
139 [[nodiscard]] bool
140 has_parent_factory() const noexcept
141 {
142 return nullptr != m_parent_factory;
143 }
144
145 //! Getter for the parent's type upcaster.
146 //!
147 //! @throw so_5::exception_t if there is no parent's type.
148 //!
149 //! @return upcaster object for the parent type.
151 parent_upcaster( message_mutability_t mutability ) const
152 {
154 SO_5_THROW_EXCEPTION(
156 "no parent upcaster_factory" );
157
158 return (*m_parent_factory)( mutability );
159 }
160 };
161
162//
163// root_base_t
164//
165/*!
166 * @brief Type to be the actual base class of all hierarchies.
167 *
168 * This is a non-template part of root_t<T> class.
169 *
170 * The main purpose of this class is to hold the top-level upcaster-factory.
171 */
172class root_base_t : public message_t
173 {
174 //! The top-level upcaster-factory for the current hierarchy.
175 //!
176 //! @note
177 //! This pointer will be updated several times.
178 //! The constructor of every derived class will update it.
179 upcaster_factory_t m_factory{};
180
181 public:
182 //! Getter for the stored upcaster-factory.
183 [[nodiscard]] upcaster_factory_t
185 {
186 return m_factory;
187 }
188
189 //! Setter for the upcaster-factory.
190 //!
191 //! @note
192 //! The old stored value will be lost.
193 void
195 upcaster_factory_t factory) noexcept
196 {
197 m_factory = factory;
198 }
199 };
200
201} /* namespace impl */
202
203//
204// root_t
205//
206/*!
207 * @brief The base class that starts a separate hierarchy.
208 *
209 * Usage example:
210 * @code
211 * class basic_message : public so_5::extra::msg_hierarchy::root_t< basic_message >
212 * {
213 * ... // Some domain-specific content.
214 * };
215 * @endcode
216 *
217 * @tparam Base User-defined type to be the root of the hierarchy.
218 * NOTE: mutability flag should not be used here. It means that
219 * `root_t<my_message>` is OK, but `root_t<so_5::mutable_msg<my_message>>` is an error.
220 */
221template<typename Base>
222class root_t : public impl::root_base_t
223 {
224 static_assert( !::so_5::is_mutable_message< Base >::value,
225 "the Base can't be mutable_msg<T>" );
226
227 public:
228 //! Method that creates the root upcaster-object.
229 //!
230 //! @note
231 //! This method is intended for internal usage of msg_hierarchy implementation.
232 //! Please do not call it in applicaton code.
234 so_make_upcaster_root( ::so_5::message_mutability_t mutability ) noexcept
235 {
237 return { typeid(::so_5::mutable_msg<Base>), nullptr };
238 else
239 return { typeid(Base), nullptr };
240 }
241
242 //! Constructor.
243 //!
244 //! Sets the root's upcaster-factory.
250 };
251
252namespace impl
253{
254
255//! Metafunction for checking presence of so_make_upcaster method.
256template< typename B, typename = std::void_t<> >
258
259//! Metafunction for checking presence of so_make_upcaster method.
260//!
261//! This is a specialization for case when type B has so_make_upcaster method.
262template< typename B >
264 B, std::void_t< decltype(&B::so_make_upcaster) >
265> : public std::true_type {};
266
267} /* namespace impl */
268
269//
270// node_t
271//
272/*!
273 * @brief A special mixin to be used for every derived class in a hierarchy.
274 *
275 * The main purpose of this class is to provide so_make_upcaster that is
276 * required for hierarchy traversal.
277 *
278 * Usage example:
279 * @code
280 * // The root of the hierarchy.
281 * struct basic : public so_5::extra::msg_hierarchy::root_t< basic >
282 * {
283 * ... // Some data and methods.
284 * };
285 *
286 * // A derived message.
287 * // Should have two base classes: one is `basic` (that is the root),
288 * // another is the node_t mixin.
289 * // NOTE the use of public inheritance from node_t.
290 * struct device_type_A : public basic, public so_5::extra::msg_hierarchy::node_t< device_type_A, basic >
291 * {
292 * ... // Some data and methods.
293 *
294 * // The constructor should call node_t's constructor.
295 * device_type_A()
296 * : so_5::extra::msg_hierarchy::node_t< device_type_A, basic >{ *this }
297 * {}
298 * };
299 *
300 * // Another derived message.
301 * struct device_type_B : public basic, public so_5::extra::msg_hierarchy::node_t< device_type_B, basic >
302 * {
303 * ... // Some data and methods.
304 *
305 * // The constructor should call node_t's constructor.
306 * device_type_B()
307 * : so_5::extra::msg_hierarchy::node_t< device_type_B, basic >{ *this }
308 * {}
309 * };
310 *
311 * // Another level in the hierarchy.
312 * struct device_vendor_X : public device_type_A, public so_5::extra::msg_hierarchy< device_vendor_X, device_type_A >
313 * {
314 * ... // Some data and methods.
315 *
316 * // The constructor should call node_t's constructor.
317 * device_vendor_X()
318 * : so_5::extra::msg_hierarchy::node_t< device_vendor_X, device_type_A >{ *this }
319 * {}
320 * };
321 * @endcode
322 *
323 * @attention
324 * It's important to use public inheritance for node_t mixin.
325 *
326 * @attention
327 * It's important to call node_t's constructor in the constructor of your class!
328 *
329 * @note
330 * This is an empty mixin class that doesn't add any size overhead to your classes
331 * because of empty base optimization.
332 *
333 * @tparam Derived type for that node_t will be a mixin.
334 * @tparam Base type that has to be a base type for Derived.
335 */
336template<typename Derived, typename Base>
338 {
339 static_assert( !::so_5::is_mutable_message< Base >::value,
340 "the Base can't be mutable_msg<T>" );
341
342 static_assert( !::so_5::is_mutable_message< Derived >::value,
343 "the Derived can't be mutable_msg<T>" );
344
345 public:
346 //! Helper method for obtain message-upcaster object for type Derived.
347 //!
348 //! This method will be a part of Derived type.
350 so_make_upcaster( message_mutability_t mutability ) noexcept
351 {
352 if constexpr( impl::has_so_make_upcaster_method<Base>::value )
353 {
354 const auto upcaster = &Base::so_make_upcaster;
356 return { typeid(::so_5::mutable_msg<Derived>), upcaster };
357 else
358 return { typeid(Derived), upcaster };
359 }
360 else
361 {
362 const auto upcaster = &Base::so_make_upcaster_root;
364 return { typeid(::so_5::mutable_msg<Derived>), upcaster };
365 else
366 return { typeid(Derived), upcaster };
367 }
368 }
369
370 //! Initializing constructor.
371 node_t( Derived & derived )
372 {
373 static_assert(
376
378 }
379 };
380
381namespace impl
382{
383
384/*!
385 * @brief Type of numeric ID for consumer_id.
386 */
388
389//! Special value that means that a consumer_id is not valid.
391
392//
393// demuxing_controller_iface_t
394//
395/*!
396 * @brief Interface for demuxing_controller entity.
397 */
399 {
400 public:
401 virtual ~demuxing_controller_iface_t() noexcept = default;
402
403 //! Get a reference to SObjectizer Environment for that demuxer has been
404 //! created.
405 [[nodiscard]]
406 virtual ::so_5::environment_t &
407 environment() const noexcept = 0;
408
409 //! Notification for destruction of a particular consumer.
410 //!
411 //! This method will be called in the destructor of every consumer.
412 //!
413 //! It's expected than the actual demuxer_controller will clean up
414 //! all resources associated with this consumer.
415 //!
416 //! @note
417 //! It's important that this method is noexcept, because it's called
418 //! in noexcept context (like destructor of a consumer object).
419 virtual void
421 //! ID of the destroyed consumer.
422 consumer_numeric_id_t id ) noexcept = 0;
423
424 //! Get type of sending_mbox for the demuxer.
425 [[nodiscard]]
426 virtual ::so_5::mbox_type_t
427 mbox_type() const noexcept = 0;
428
429 //! Create a receiving mbox for a consumer.
430 [[nodiscard]] virtual ::so_5::mbox_t
432 //! ID of consumer for that new receiving mbox has to be obtained.
434 //! Message type to be received from that mbox.
435 const std::type_index & msg_type ) = 0;
436
437 //! Delivery of a message.
438 //!
439 //! @note
440 //! This method mimics so_5::abstract_message_box_t::do_deliver_message method.
441 virtual void
443 //! Can the delivery blocks the current thread?
444 message_delivery_mode_t delivery_mode,
445 //! Type of the message to deliver.
446 const std::type_index & msg_type,
447 //! A message instance to be delivered.
448 const message_ref_t & message,
449 //! Current deep of overlimit reaction recursion.
450 unsigned int redirection_deep ) = 0;
451 };
452
453//
454// demuxing_controller_iface_shptr_t
455//
456//! Alias for shared_ptr to demuxing_controller_iface.
459
460//
461// basic_demuxing_controller_t
462//
463/*!
464 * @brief Partial implementation of demuxing_controller_iface.
465 *
466 * Implements functionality that not depends on the mbox_type of
467 * the demuxer.
468 *
469 * @tparam Root type of the hierarchy root.
470 * @tparam Lock_Type type of mutex for thread safety (a type similar to
471 * std::shared_mutex). It should be a DefaultConstructible object.
472 */
473template< typename Root, typename Lock_Type >
475 {
476 protected:
477 //! SObjectizer Environment for that demuxer has been created.
478 //!
479 //! It's expected that this reference will outlast the controller object.
481
482 //! Lock for thread-safety.
483 Lock_Type m_lock;
484
485 //! Type of mbox for the demuxer.
487
488 //! Counter for generation of customer's IDs.
490
491 public:
492 //! Initializing constructor.
494 //! SObjectizer Environment for that the demuxer has been created.
495 ::so_5::outliving_reference_t< ::so_5::environment_t > env,
496 //! Type of mbox for the demuxer.
497 ::so_5::mbox_type_t mbox_type )
498 : m_env{ env.get() }
500 {}
501
509
511 environment() const noexcept override
512 {
513 return m_env;
514 }
515
517 mbox_type() const noexcept override
518 {
519 return m_mbox_type;
520 }
521 };
522
523//
524// demuxing_controller_shptr_t
525//
526//! Alias of shared_ptr for basic_demuxing_controller.
527template< typename Root, typename Lock_Type >
530
531//
532// controller_consumers_mixin_t
533//
534/*!
535 * @brief Helper type to be used as mixin for actual demuxing controllers.
536 *
537 * Contains map of consumers and implements delivery procedure for
538 * immutable messages.
539 */
541 {
542 //! Type of map of mboxes for one consumer.
544
545 //! Type of map of all consumers.
549 >;
550
551 //! Map of all consumers.
553
554 /*!
555 * @brief Perform delivery of the message.
556 *
557 * It's assumed that all necessary check have been performed earlier.
558 */
559 void
561 //! How message has to be delivered.
562 ::so_5::message_delivery_mode_t delivery_mode,
563 //! Message to be delivered.
564 const ::so_5::message_ref_t & message,
565 //! Redirection deep for overload control.
566 unsigned int redirection_deep,
567 //! The pointer to the root of the hierarchy for this message.
568 const root_base_t * root )
569 {
570 const auto msg_mutabilty_flag = message_mutability( *root );
571
572 // Main delivery loop.
573 for( const auto & [id, consumer_map] : m_consumers_with_mboxes )
574 {
575 // Try to deliver message by its actual type and them
576 // trying to going hierarchy up.
577 auto upcaster = root->so_message_upcaster_factory()(
578 msg_mutabilty_flag );
579
580 bool delivery_finished = false;
581 do
582 {
583 const auto type_to_find = upcaster.self_type();
584 if( const auto it = consumer_map.find( type_to_find );
585 it != consumer_map.end() )
586 {
587 // Only one delivery for every consumer.
588 delivery_finished = true;
589 it->second->do_deliver_message(
590 delivery_mode,
591 type_to_find,
592 message,
593 redirection_deep );
594 }
595 else
596 {
597 delivery_finished = !upcaster.has_parent_factory();
598 if( !delivery_finished )
599 {
600 // It's not the root yet, try to go one level up.
601 upcaster = upcaster.parent_upcaster( msg_mutabilty_flag );
602 }
603 }
604 } while( !delivery_finished );
605 }
606 }
607 };
608
609//
610// mpmc_demuxing_controller_t
611//
612/*!
613 * Implementation of demuxer_controller interface for
614 * multi-producer/multi-consumer case.
615 *
616 * @note
617 * See description of demuxing_controller_iface_t for information
618 * about Root and Lock_Type template parameters.
619 */
620template< typename Root, typename Lock_Type >
621class multi_consumer_demuxing_controller_t final
622 : public basic_demuxing_controller_t< Root, Lock_Type >
624 {
625 //! Alias for basic_demuxing_controller.
626 using base_type_t = basic_demuxing_controller_t< Root, Lock_Type >;
627
628 public:
629 //! Initializing constructor.
631 //! SObjectizer Environment for that the demuxer has been created.
632 ::so_5::outliving_reference_t< ::so_5::environment_t > env )
633 : base_type_t{ env, ::so_5::mbox_type_t::multi_producer_multi_consumer }
634 {}
635
636 [[nodiscard]] so_5::mbox_t
639 const std::type_index & msg_type ) override
640 {
641 std::lock_guard< Lock_Type > lock{ this->m_lock };
642
643 auto [it_consumer, _] = this->m_consumers_with_mboxes.emplace(
644 id, one_consumer_mboxes_map_t{} );
645 auto & consumer_map = it_consumer->second;
646
647 auto it_msg = consumer_map.find( msg_type );
648 if( it_msg == consumer_map.end() )
649 {
650 it_msg = consumer_map.emplace(
651 msg_type,
652 this->m_env.create_mbox() ).first;
653 }
654
655 return it_msg->second;
656 }
657
658 void
659 consumer_destroyed( consumer_numeric_id_t id ) noexcept override
660 {
661 std::lock_guard< Lock_Type > lock{ this->m_lock };
662
663 this->m_consumers_with_mboxes.erase( id );
664 }
665
666 void
668 ::so_5::message_delivery_mode_t delivery_mode,
669 const std::type_index & msg_type,
670 const ::so_5::message_ref_t & message,
671 unsigned int redirection_deep ) override
672 {
673 namespace err_ns = ::so_5::extra::msg_hierarchy::errors;
674
675 // Do all necessary checks first...
676 if( ::so_5::message_mutability_t::immutable_message !=
677 message_mutability( message ) )
678 SO_5_THROW_EXCEPTION(
679 ::so_5::rc_mutable_msg_cannot_be_delivered_via_mpmc_mbox,
680 "an attempt to deliver mutable message via MPMC mbox"
681 ", msg_type=" + std::string(msg_type.name()) );
682
683 const ::so_5::message_t * raw_msg = message.get();
684 if( !raw_msg )
685 SO_5_THROW_EXCEPTION(
686 err_ns::rc_signal_cannot_be_delivered,
687 "signal can't be handled by msg_hierarchy's demuxer" );
688
689 const root_base_t * root = dynamic_cast<const root_base_t *>(raw_msg);
690 if( !root )
691 SO_5_THROW_EXCEPTION(
692 err_ns::rc_message_is_not_derived_from_root,
693 "a message type has to be derived from root_t" );
694
695 // ...the object has to be locked for the delivery procedure...
696 std::shared_lock< Lock_Type > lock{ this->m_lock };
697
698 // ...now the message can be delivered.
699 this->do_delivery_procedure_for_immutable_message(
700 delivery_mode,
701 message,
702 redirection_deep,
703 root );
704 }
705 };
706
707//
708// single_dest_info_t
709//
710/*!
711 * @brief Information about a single destination for a mutable message.
712 */
714 {
715 //! Mbox to be used for delivery.
717
718 //! Subscription type to be used for delivery.
720
721 //! Initializing constructor.
723 so_5::mbox_t dest_mbox,
724 std::type_index subscription_type )
727 {}
728 };
729
730//
731// mpsc_demuxing_controller_t
732//
733/*!
734 * Implementation of demuxer_controller interface for
735 * multi-producer/single-consumer case.
736 *
737 * @note
738 * See description of demuxing_controller_iface_t for information
739 * about Root and Lock_Type template parameters.
740 */
741template< typename Root, typename Lock_Type >
742class single_consumer_demuxing_controller_t final
743 : public basic_demuxing_controller_t< Root, Lock_Type >
745 {
746 //! Alias for basic_demuxing_controller.
747 using base_type_t = basic_demuxing_controller_t< Root, Lock_Type >;
748
749 public:
750 //! Initializing constructor.
752 //! SObjectizer Environment for that the demuxer has been created.
753 ::so_5::outliving_reference_t< ::so_5::environment_t > env )
754 : base_type_t{ env, ::so_5::mbox_type_t::multi_producer_single_consumer }
755 {}
756
757 [[nodiscard]] so_5::mbox_t
760 const std::type_index & msg_type ) override
761 {
762 std::lock_guard< Lock_Type > lock{ this->m_lock };
763
764 auto [it_consumer, _] = this->m_consumers_with_mboxes.emplace(
765 id, one_consumer_mboxes_map_t{} );
766 auto & consumer_map = it_consumer->second;
767
768 auto it_msg = consumer_map.find( msg_type );
769 if( it_msg == consumer_map.end() )
770 {
771 it_msg = consumer_map.emplace(
772 msg_type,
773 ::so_5::make_unique_subscribers_mbox< Lock_Type >( this->m_env ) )
774 .first;
775 }
776
777 return it_msg->second;
778 }
779
780 void
781 consumer_destroyed( consumer_numeric_id_t id ) noexcept override
782 {
783 std::lock_guard< Lock_Type > lock{ this->m_lock };
784
785 this->m_consumers_with_mboxes.erase( id );
786 }
787
788 void
790 message_delivery_mode_t delivery_mode,
791 const std::type_index & /*msg_type*/,
792 const message_ref_t & message,
793 unsigned int redirection_deep ) override
794 {
795 namespace err_ns = ::so_5::extra::msg_hierarchy::errors;
796
797 // Do all necessary checks first...
798 const ::so_5::message_t * raw_msg = message.get();
799 if( !raw_msg )
800 SO_5_THROW_EXCEPTION(
801 err_ns::rc_signal_cannot_be_delivered,
802 "signal can't be handled by msg_hierarchy's demuxer" );
803
804 const root_base_t * root = dynamic_cast<const root_base_t *>(raw_msg);
805 if( !root )
806 SO_5_THROW_EXCEPTION(
807 err_ns::rc_message_is_not_derived_from_root,
808 "a message type has to be derived from root_t" );
809
810 const auto msg_mutabilty_flag = message_mutability( *root );
811
812 // ...the object has to be locked for the delivery procedure...
813 std::shared_lock< Lock_Type > lock{ this->m_lock };
814
815 if( ::so_5::message_mutability_t::mutable_message == msg_mutabilty_flag )
816 {
817 // Is there a single subscriber for a message?
818 const auto single_dest_info =
819 detect_receiver_for_mutable_msg_or_throw( root );
820 if( single_dest_info )
821 // The single subscriber is found, the message has to be
822 // delivered to it.
823 single_dest_info->m_dest_mbox->do_deliver_message(
824 delivery_mode,
825 single_dest_info->m_subscription_type,
826 message,
827 redirection_deep );
828 }
829 else
830 {
831 // ...now the immutable message can be delivered.
832 this->do_delivery_procedure_for_immutable_message(
833 delivery_mode,
834 message,
835 redirection_deep,
836 root );
837 }
838 }
839
840 private:
841 //! Try to find a single destination for a mutable message.
842 //!
843 //! @throw so_5::exception_t if there are more than one available destinations.
844 //!
845 //! @return non-empty value of a single destination has been found.
846 [[nodiscard]]
849 //! Message pointer that is casted to the hierarchy root.
850 const root_base_t * root ) const
851 {
852 std::optional< single_dest_info_t > result;
853
854 // Main loop for subscribers detection.
855 for( const auto & [id, consumer_map] : this->m_consumers_with_mboxes )
856 {
857 // Try to deliver message by its actual type and them
858 // trying to going hierarchy up.
859 auto upcaster = root->so_message_upcaster_factory()(
860 ::so_5::message_mutability_t::mutable_message );
861
862 bool delivery_finished = false;
863 do
864 {
865 const auto type_to_find = upcaster.self_type();
866 if( const auto it = consumer_map.find( type_to_find );
867 it != consumer_map.end() )
868 {
869 if( result )
870 {
871 namespace err_ns = ::so_5::extra::msg_hierarchy::errors;
872 // Another subscriber detected. The message
873 // can't be delivered.
874 SO_5_THROW_EXCEPTION(
875 err_ns::rc_more_than_one_subscriber_for_mutable_msg,
876 "more than one subscriber detected for "
877 "a mutable message" );
878 }
879 else
880 {
881 result = single_dest_info_t{ it->second, type_to_find };
882 }
883
884 // Only one delivery for every consumer.
885 delivery_finished = true;
886 }
887 else
888 {
889 delivery_finished = !upcaster.has_parent_factory();
890 if( !delivery_finished )
891 {
892 // It's not the root yet, try to go one level up.
893 upcaster = upcaster.parent_upcaster(
894 ::so_5::message_mutability_t::mutable_message );
895 }
896 }
897 } while( !delivery_finished );
898 }
899
900 return result;
901 }
902 };
903
904//
905// basic_sending_mbox_t
906//
907/*!
908 * @brief Basic implementation for all kinds of sending_mboxes.
909 */
911 : public ::so_5::abstract_message_box_t
912 {
913 //! Controller to be used.
915
916 //! ID of the mbox.
918
919 protected:
920 /*!
921 * @brief Initializing constructor.
922 *
923 * It's protected to be accessible for derived classes only.
924 */
926 //! Controller to be used.
927 demuxing_controller_iface_shptr_t controller,
928 //! ID for this mbox.
929 ::so_5::mbox_id_t id )
931 , m_id{ id }
932 {}
933
934 public:
935 ::so_5::mbox_id_t
936 id() const override
937 {
938 return m_id;
939 }
940
941 void
943 const std::type_index & /*type_index*/,
944 ::so_5::abstract_message_sink_t & /*subscriber*/ ) override
945 {
946 SO_5_THROW_EXCEPTION( ::so_5::rc_not_implemented,
947 "subscribe_event_handler is not supported for this type of mbox" );
948 }
949
950 void
952 const std::type_index & /*type_index*/,
953 abstract_message_sink_t & /*subscriber*/ ) noexcept override
954 {
955 // Nothing to do.
956 }
957
958 void
960 message_delivery_mode_t delivery_mode,
961 const std::type_index & msg_type,
962 const message_ref_t & message,
963 unsigned int redirection_deep ) override
964 {
965 m_controller->do_deliver_message(
966 delivery_mode,
967 msg_type,
968 message,
969 redirection_deep );
970 }
971
972 void
974 const std::type_index & /*msg_type*/,
975 const delivery_filter_t & /*filter*/,
976 abstract_message_sink_t & /*subscriber*/ ) override
977 {
978 SO_5_THROW_EXCEPTION( ::so_5::rc_not_implemented,
979 "set_delivery_filter is not supported for this type of mbox" );
980 }
981
982 virtual void
984 const std::type_index & /*msg_type*/,
985 abstract_message_sink_t & /*subscriber*/ ) noexcept override
986 {
987 // Nothing to do.
988 }
989
990 [[nodiscard]]
992 environment() const noexcept override
993 {
994 return m_controller->environment();
995 }
996 };
997
998//
999// multi_consumer_sending_mbox_t
1000//
1001//! Implementation of sending mbox for multi-producer/multi-consumer case.
1002template< typename Root >
1003class multi_consumer_sending_mbox_t final
1004 : public basic_sending_mbox_t
1005 {
1006 public:
1007 //! Initializing constructor.
1009 //! Controller to be used.
1010 demuxing_controller_iface_shptr_t controller,
1011 //! ID for this mbox.
1012 ::so_5::mbox_id_t id )
1013 : basic_sending_mbox_t{ std::move(controller), id }
1014 {}
1015
1016 std::string
1017 query_name() const override
1018 {
1019 std::ostringstream s;
1020 s << "<mbox:type=MSG_HIERARCHY_SENDING_MPMC:root="
1021 << typeid(Root).name()
1022 << ":id=" << this->id() << ">";
1023 return s.str();
1024 }
1025
1026 ::so_5::mbox_type_t
1027 type() const override
1028 {
1029 return ::so_5::mbox_type_t::multi_producer_multi_consumer;
1030 }
1031 };
1032
1033//
1034// single_consumer_sending_mbox_t
1035//
1036//! Implementation of sending mbox for multi-producer/single-consumer case.
1037template< typename Root >
1038class single_consumer_sending_mbox_t final
1039 : public basic_sending_mbox_t
1040 {
1041 public:
1042 //! Initializing constructor.
1044 //! Controller to be used.
1045 demuxing_controller_iface_shptr_t controller,
1046 //! ID for this mbox.
1047 ::so_5::mbox_id_t id )
1048 : basic_sending_mbox_t{ std::move(controller), id }
1049 {}
1050
1051 std::string
1052 query_name() const override
1053 {
1054 std::ostringstream s;
1055 s << "<mbox:type=MSG_HIERARCHY_SENDING_MPMS:root="
1056 << typeid(Root).name()
1057 << ":id=" << this->id() << ">";
1058 return s.str();
1059 }
1060
1061 ::so_5::mbox_type_t
1062 type() const override
1063 {
1064 return ::so_5::mbox_type_t::multi_producer_single_consumer;
1065 }
1066 };
1067
1068} /* namespace impl */
1069
1070//
1071//
1072// consumer_t forward decl.
1073//
1074template< typename Root >
1075class consumer_t;
1076
1077//
1078// demuxer_t definition
1079//
1080/*!
1081 * @brief Demuxer for hierarchy of messages.
1082 *
1083 * A demuxer provides a single _sending_mbox_ for all messages. An outgoing
1084 * message has to be sent to this sending_mbox.
1085 *
1086 * To receive a message it's necessary to do the following actions:
1087 *
1088 * - create a consumer instance by calling allocate_consumer() method;
1089 * - call consumer_t::receiving_mbox() for the consumer instance to get
1090 * a mbox for a particular type of a message.
1091 *
1092 * The dexumer can be either multi-producer/multi-consumer or
1093 * multi-producer/single-consumer. This type is specified in the constructor
1094 * and can't be changed later. A multi-consumer demuxer prohibits delivery
1095 * of mutable messages.
1096 *
1097 * Usage example:
1098 * @code
1099 * struct basic : public so_5::extra::msg_hierarchy::root_t< basic > {...};
1100 *
1101 * struct device_type_A : public basic, public so_5::extra::msg_hierarchy::node_t< device_type_A, basic > {...}
1102 * ... // Other types of messages.
1103 *
1104 * class message_receiver final : public so_5::agent_t {
1105 * // Consumer handle to work with incoming messages.
1106 * so_5::extra::msg_hierarchy::consumer_t< basic > m_consumer;
1107 *
1108 * ...
1109 * public:
1110 * message_receiver( context_t ctx, so_5::extra::msg_hierarchy::demuxer_t< basic > & demuxer )
1111 * : so_5::agent_t{ std::move(ctx) }
1112 * , m_consumer{
1113 * // Allocation of consumer instance for this agent.
1114 * demuxer.allocate_consumer() }
1115 * {}
1116 * ...
1117 * void so_define_agent() override
1118 * {
1119 * // Obtaining receiving_mbox for message subscriptions.
1120 * so_subscribe( m_consumer.receiving_mbox< basic >() )
1121 * .event( ... );
1122 *
1123 * so_subscribe( m_controller.receiving_mbox< device_type_A >() )
1124 * .event( ... )
1125 * .event( ... );
1126 * }
1127 * };
1128 * ...
1129 * so_5::environment_t & env = ...;
1130 * // Instance of demuxer.
1131 * so_5::extra::msg_hierarchy::demuxer_t< basic > demuxer{ env, so_5::extra::msg_hierarchy::multi_consumer };
1132 * // Registration of agents.
1133 * env.register_agent_as_coop(
1134 * env.make_agent< message_receiver >( demuxer ) );
1135 * ...
1136 * @endcode
1137 *
1138 * @attention
1139 * The demuxer_t is a Moveable, but not Copyable class.
1140 *
1141 * @note
1142 * A demuxer object can be seen as a temprary proxy for a special controller object.
1143 * This controller object will live as long as there are live references to the
1144 * sending_mbox and/or any of receiving_mboxes. But demuxer object can be safely
1145 * destroyed if it's not needed anymore. For example:
1146 * @code
1147 * so_5::environment_t & env = ...;
1148 * env.introduce_coop( []( so_5::coop_t & coop ) {
1149 * // A demuxer object is needed only during the creation of agents.
1150 * so_5::extra::msg_hierarchy::demuxer_t< basic > demuxer{ coop.environment(), so_5::extra::msg_hierarchy::multi_consumer };
1151 *
1152 * coop.make_agent< message_receiver >( demuxer );
1153 * coop.make_agent< message_sender >( demuxer );
1154 * ...
1155 * // The demuxer object is no more needed and can be destroyed now.
1156 * // The underlying controller object will live while message_receiver
1157 * // and message_sender agents are live.
1158 * } );
1159 * @endcode
1160 *
1161 * @tparam Root the type of the hierarchy root. This type has to be derived from root_t<T>
1162 * template class. This type should not use `so_5::mutable_msg` modifier. It means that
1163 * @code
1164 * struct my_root : public so_5::extra::msg_hierarchy::root_t< my_root >{...};
1165* so_5::extra::msg_hierarchy::demuxer_t< my_root > demuxer{...};
1166 * @endcode
1167 * Is OK, but this is an error:
1168 * @code
1169 * struct my_root : public so_5::extra::msg_hierarchy::root_t< my_root >{...};
1170 * so_5::extra::msg_hierarchy::demuxer_t< so_5::mutable_msg<my_root> > demuxer{...}; // ERROR!
1171 * @endcode
1172 * It you need a demuxer that allows to send a mutable message it's necessary to
1173 * pass single_consumer value to the demuxer's constructor:
1174 * @code
1175 * struct my_root : public so_5::extra::msg_hierarchy::root_t< my_root >{...};
1176 * so_5::extra::msg_hierarchy::demuxer_t< my_root > demuxer{
1177 * env,
1178 * // This flag makes multi-producer/single-consumer demuxer.
1179 * so_5::extra::msg_hierarchy::single_consumer };
1180 * @endcode
1181 *
1182 * @tparam Lock_Type type to be used for thread safety. It should be a class like std::shared_mutex.
1183 */
1184template<
1185 typename Root,
1186 typename Lock_Type = std::shared_mutex >
1188 {
1189 static_assert( std::is_base_of_v<impl::root_base_t, Root>,
1190 "the Root has to be root_t<Msg> or a type derived from root_t<Msg>" );
1191
1192 static_assert( !::so_5::is_mutable_message< Root >::value,
1193 "the Root can't be mutable_msg<T>" );
1194
1195 //! Actual demuxing_controller for this demuxer instance.
1197
1198 //! Actual sending mbox for this demuxer instance.
1199 //!
1200 //! @note
1201 //! It may be a MPMC or MPSC mbox. The type will be detected at the
1202 //! construction time. Once created it can't be changed later.
1204
1205 //! Factory to create an appropriate demuxing_controller instance.
1206 [[nodiscard]]
1209 //! SObjectizer Environment for that the demuxer has been created.
1211 //! Type of mbox for the demuxer.
1213 {
1215
1217 switch( mbox_type )
1218 {
1220 {
1222 Root, Lock_Type >;
1223
1224 result = result_t{ new controller_t{ env } };
1225 }
1226 break;
1227
1229 {
1231 Root, Lock_Type >;
1232
1233 result = result_t{ new controller_t{ env } };
1234 }
1235 break;
1236 }
1237 return result;
1238 }
1239
1240 //! Factory to create an appropriate sending_mbox instance.
1241 [[nodiscard]]
1242 static ::so_5::mbox_t
1244 //! Actual demuxing_controller object to be used for message delivery.
1246 //! SObjectizer Environment for that the demuxer has been created.
1248 //! Type of mbox for the demuxer.
1250 {
1251 const auto mbox_id = ::so_5::impl::internal_env_iface_t{ env.get() }
1253
1255 switch( mbox_type )
1256 {
1258 result = so_5::mbox_t{
1261 mbox_id )
1262 };
1263 break;
1264
1266 result = so_5::mbox_t{
1269 mbox_id )
1270 };
1271 break;
1272 }
1273
1274 return result;
1275 }
1276
1277 public:
1278 friend void
1279 swap( demuxer_t & a, demuxer_t & b ) noexcept
1280 {
1281 using std::swap;
1282
1285 }
1286
1287 //! Initializing constructor.
1289 //! SObjectizer Environment to work in.
1290 //! This reference should reman valid for the whole lifetime of the
1291 //! demuxer object.
1292 ::so_5::environment_t & env,
1293 //! Type of demuxer and its sending_mbox.
1294 //! It's expected to be so_5::extra::msg_hierarchy::multi_consumer or
1295 //! so_5::extra::msg_hierarchy::single_consumer.
1296 ::so_5::mbox_type_t mbox_type )
1297 : m_controller{
1300 mbox_type )
1301 }
1306 mbox_type )
1307 }
1308 {}
1309
1310 demuxer_t( const demuxer_t & ) = delete;
1311 demuxer_t &
1312 operator=( const demuxer_t & ) = delete;
1313
1321 demuxer_t &
1322 operator=( demuxer_t && o ) noexcept
1323 {
1324 demuxer_t tmp{ std::move(o) };
1325 swap( *this, tmp );
1326 return *this;
1327 }
1328
1329 //! Create an instance of consumer object.
1330 //!
1331 //! @note
1332 //! Every call to allocate_consumer() returns a separate instance of
1333 //! consumer object.
1334 [[nodiscard]]
1335 consumer_t< Root >
1337
1338 //! Getter for the single sending_mbox mbox.
1339 [[nodiscard]]
1340 const ::so_5::mbox_t &
1341 sending_mbox() const noexcept
1342 {
1343 return m_sending_mbox;
1344 }
1345 };
1346
1347//
1348// consumer_t
1349//
1350/*!
1351 * @brief A consumer interface for a demuxer object.
1352 *
1353 * A demuxer object (an instance of demuxer_t template class) provides access to
1354 * sending_mbox only. To receive a message it's necessary to create an instance
1355 * of a consumer and receive a special receiving_mbox from it. The template
1356 * class consumer_t represents such a consumer object.
1357 *
1358 * An instance of a consumer_t should live as long as user wants to receive
1359 * incoming message. If a consumer_t instance is destroyed then all receiving
1360 * mboxes created by this consumer will be deactivated. It means that
1361 * instances of mboxes will remain live but nothing will be sent to them.
1362 *
1363 * Because of that it's recommended to bind a consumer to an agent that requires it:
1364 * @code
1365 * struct basic : public so_5::extra::msg_hierarchy::root_t< basic >{ ... };
1366 *
1367 * class message_receiver final : public so_5::agent_t {
1368 * // An instance of consumer_t.
1369 * // This instance will live as long as message_receiver agent itself.
1370 * so_5::extra::msg_hierarchy::consumer_t< basic > m_consumer;
1371 * ...
1372 * public:
1373 * message_receiver( context_t ctx, so_5::extra::msg_hierarchy::demuxer_t< basic > & demuxer )
1374 * : so_5::agent_t{ std::move(ctx) }
1375 * // Create an instance of a consumer for the demuxer.
1376 * , m_consumer{ demuxer.allocate_consumer() }
1377 * {}
1378 * ...
1379 * }
1380 * @endcode
1381 *
1382 * @note
1383 * All receiving_mboxes created by the same consumer object are bound together.
1384 * If a message can be received from several of them only one mbox will be
1385 * selected for the delivery. An example:
1386 * @code
1387 * struct basic : public so_5::extra::msg_hierarchy::root_t< basic >{ ... };
1388 *
1389 * struct device_type_A : public basic, public so_5::extra::msg_hierarchy::node_t< device_type_A, basic >{ ... };
1390 * struct vendor_X_device_Y : public device_type_A, public so_5::extra::msg_hierarchy::node_t< vendor_X_device_Y, device_type_A >{ ... };
1391 *
1392 * struct vendor_Z_device_V : public device_type_A, public so_5::extra::msg_hierarchy::node_t< vendor_V_device_Z, device_type_A >{ ... };
1393 *
1394 * struct control_code : public basic, public so_5::extra::msg_hierarchy::node_t< control_code, basic >{ ... };
1395 *
1396 * class demo final : public so_5::agent_t {
1397 * so_5::extra::msg_hierarchy::consumer_t< basic > m_consumer;
1398 *
1399 * const so_5::mbox_t m_sending_mbox;
1400 *
1401 * public:
1402 * demo( context_t ctx, so_5::extra::msg_hierarchy::demuxer_t< basic > & demuxer )
1403 * : so_5::agent_t{ std::move(ctx) }
1404 * , m_consumer{ demuxer.allocate_consumer() }
1405 * , m_sending_mbox{ demuxer.sending_mbox() }
1406 * {}
1407 * ...
1408 * void so_define_agent() override {
1409 * so_subscribe( m_consumer.receiving_mbox< basic >() )
1410 * .event( [this]( mhood_t<basic> & cmd) {
1411 * ... // Handler (1)
1412 * } );
1413 *
1414 * so_subscribe( m_consumer.receiving_mbox< device_type_A >() )
1415 * .event( [this]( mhood_t<device_type_A> & cmd) {
1416 * ... // Handler (2)
1417 * } );
1418 *
1419 * so_subscribe( m_consumer.receiving_mbox< vendor_X_device_Y >() )
1420 * .event( [this]( mhood_t<vendor_X_device_Y> & cmd) {
1421 * ... // Handler (3)
1422 * } );
1423 * }
1424 * ...
1425 * void so_evt_start() override {
1426 * so_5::send< vendor_X_device_Y >( m_sending_mbox, ... );
1427 *
1428 * so_5::send< vendor_Z_device_V >( m_sending_mbox, ... );
1429 *
1430 * so_5::send< control_code >( m_sending_mbox, ... );
1431 * }
1432 * };
1433 * @endcode
1434 * The message `vendor_X_device_Y` will be delivered to the handler (3) because
1435 * it's the best match for the message type. The message `vendor_Z_device_V` will
1436 * be delivered to the handler (2) as `device_type_A` message. And the message
1437 * `control_code` will be delivered to the handler (1) as `basic` message.
1438 *
1439 * @attention
1440 * The consumer_t is a Moveable, but not Copyable class.
1441 */
1442template< typename Root >
1444 {
1445 template< typename Demuxer_Root, typename Demuxer_Lock_Type >
1446 friend class demuxer_t;
1447
1448 //! Actual demuxing_controller to be used for message exchange.
1450
1451 //! ID for this consumer.
1453
1454 //! Initializing constructor.
1456 //! Actual demuxing_controller to be used for message exchange.
1457 impl::demuxing_controller_iface_shptr_t controller,
1458 //! ID for this consumer.
1459 impl::consumer_numeric_id_t id )
1461 , m_id{ id }
1462 {}
1463
1464 public:
1465 friend void
1466 swap( consumer_t & a, consumer_t & b ) noexcept
1467 {
1468 using std::swap;
1469
1471 swap( a.m_id, b.m_id );
1472 }
1473
1475 {
1476 if( m_controller )
1477 {
1479 }
1480 }
1481
1482 consumer_t( const consumer_t & ) = delete;
1483 consumer_t &
1484 operator=( const consumer_t & ) = delete;
1485
1493
1494 consumer_t &
1495 operator=( consumer_t && o ) noexcept
1496 {
1497 consumer_t tmp{ std::move(o) };
1498 swap( *this, tmp );
1499 return *this;
1500 }
1501
1502 //! Acquire a receiving mbox for the specified message type.
1503 //!
1504 //! Usage example:
1505 //! @code
1506 //! class demo final : public so_5::agent_t {
1507 //! so_5::extra::msg_hierarchy::consumer_t< basic > m_consumer;
1508 //!
1509 //! const so_5::mbox_t m_sending_mbox;
1510 //!
1511 //! public:
1512 //! demo( context_t ctx, so_5::extra::msg_hierarchy::demuxer_t< basic > & demuxer )
1513 //! : so_5::agent_t{ std::move(ctx) }
1514 //! , m_consumer{ demuxer.allocate_consumer() }
1515 //! , m_sending_mbox{ demuxer.sending_mbox() }
1516 //! {}
1517 //! ...
1518 //! void so_define_agent() override {
1519 //! so_subscribe( m_consumer.receiving_mbox< basic >() )
1520 //! .event( [this]( mhood_t<basic> & cmd) {
1521 //! ... // Handler (1)
1522 //! } );
1523 //!
1524 //! so_subscribe( m_consumer.receiving_mbox< device_type_A >() )
1525 //! .event( [this]( mhood_t<device_type_A> & cmd) {
1526 //! ... // Handler (2)
1527 //! } );
1528 //!
1529 //! so_subscribe( m_consumer.receiving_mbox< vendor_X_device_Y >() )
1530 //! .event( [this]( mhood_t<vendor_X_device_Y> & cmd) {
1531 //! ... // Handler (3)
1532 //! } );
1533 //! }
1534 //! };
1535 //! @endcode
1536 //!
1537 //! @note
1538 //! It's necessary to use `so_5::mutable_msg` modifier to get a receiving mbox
1539 //! for a mutable message:
1540 //! @code
1541 //! so_subscribe( m_consumer.receiving_mbox< so_5::mutable_msg< control_code > >() )
1542 //! .event( [this]( mutable_mhood_t<control_code> cmd ) {
1543 //! ...
1544 //! } );
1545 //! @endcode
1546 //!
1547 template< typename Msg_Type >
1548 [[nodiscard]] so_5::mbox_t
1550 {
1551 if constexpr( ::so_5::is_mutable_message< Msg_Type >::value )
1552 {
1553 // There we have Msg_Type as `so_5::mutable_msg<Payload_Type>` and have
1554 // to extract and handle Payload_Type instead of Msg_Type.
1555 using payload_type =
1557
1558 static_assert(
1561 "Msg_Type has to be a Root type or a type derived from Root" );
1562
1567 std::string{ "receiving_mbox can't be created for a mutable msg: " }
1568 + typeid(Msg_Type).name() );
1569 }
1570 else
1571 {
1572 static_assert( (std::is_same_v<Msg_Type, Root> || std::is_base_of_v<Root, Msg_Type>),
1573 "Msg_Type has to be a Root type or a type derived from Root" );
1574 }
1575
1577 m_id,
1579 }
1580 };
1581
1582//
1583// demuxer_t implementation
1584//
1585
1586template< typename Root, typename Lock_Type >
1587[[nodiscard]] consumer_t< Root >
1588demuxer_t< Root, Lock_Type >::allocate_consumer()
1589 {
1590 return consumer_t< Root >{
1593 };
1594 }
1595
1596/*!
1597 * @brief Indicator that a demuxer with Multi-Producer/Multi-Consumer mboxes
1598 * has to be created.
1599 */
1600inline constexpr ::so_5::mbox_type_t multi_consumer =
1602
1603/*!
1604 * @brief Indicator that a demuxer with Multi-Producer/Single-Consumer mboxes
1605 * has to be created.
1606 */
1607inline constexpr ::so_5::mbox_type_t single_consumer =
1609
1610} /* namespace so_5::extra::msg_hierarchy */
A consumer interface for a demuxer object.
Definition pub.hpp:1444
so_5::mbox_t receiving_mbox()
Acquire a receiving mbox for the specified message type.
Definition pub.hpp:1549
friend void swap(consumer_t &a, consumer_t &b) noexcept
Definition pub.hpp:1466
consumer_t(consumer_t &&o) noexcept
Definition pub.hpp:1486
consumer_t(const consumer_t &)=delete
impl::demuxing_controller_iface_shptr_t m_controller
Actual demuxing_controller to be used for message exchange.
Definition pub.hpp:1449
impl::consumer_numeric_id_t m_id
ID for this consumer.
Definition pub.hpp:1452
consumer_t & operator=(consumer_t &&o) noexcept
Definition pub.hpp:1495
consumer_t & operator=(const consumer_t &)=delete
consumer_t(impl::demuxing_controller_iface_shptr_t controller, impl::consumer_numeric_id_t id)
Initializing constructor.
Definition pub.hpp:1455
Demuxer for hierarchy of messages.
Definition pub.hpp:1188
demuxer_t(demuxer_t &&o) noexcept
Definition pub.hpp:1314
demuxer_t(const demuxer_t &)=delete
demuxer_t(::so_5::environment_t &env, ::so_5::mbox_type_t mbox_type)
Initializing constructor.
Definition pub.hpp:1288
::so_5::mbox_t m_sending_mbox
Actual sending mbox for this demuxer instance.
Definition pub.hpp:1203
static impl::demuxing_controller_shptr_t< Root, Lock_Type > make_required_demuxing_controller_object(::so_5::outliving_reference_t< ::so_5::environment_t > env, ::so_5::mbox_type_t mbox_type)
Factory to create an appropriate demuxing_controller instance.
Definition pub.hpp:1208
const ::so_5::mbox_t & sending_mbox() const noexcept
Getter for the single sending_mbox mbox.
Definition pub.hpp:1341
friend void swap(demuxer_t &a, demuxer_t &b) noexcept
Definition pub.hpp:1279
demuxer_t & operator=(demuxer_t &&o) noexcept
Definition pub.hpp:1322
impl::demuxing_controller_shptr_t< Root, Lock_Type > m_controller
Actual demuxing_controller for this demuxer instance.
Definition pub.hpp:1196
demuxer_t & operator=(const demuxer_t &)=delete
consumer_t< Root > allocate_consumer()
Create an instance of consumer object.
Definition pub.hpp:1588
::so_5::mbox_t make_required_sending_mbox(impl::demuxing_controller_iface_shptr_t controller, ::so_5::outliving_reference_t< ::so_5::environment_t > env, ::so_5::mbox_type_t mbox_type)
Factory to create an appropriate sending_mbox instance.
Definition pub.hpp:1243
Partial implementation of demuxing_controller_iface.
Definition pub.hpp:475
consumer_numeric_id_t m_consumer_id_counter
Counter for generation of customer's IDs.
Definition pub.hpp:489
::so_5::environment_t & environment() const noexcept override
Get a reference to SObjectizer Environment for that demuxer has been created.
Definition pub.hpp:511
::so_5::mbox_type_t mbox_type() const noexcept override
Get type of sending_mbox for the demuxer.
Definition pub.hpp:517
basic_demuxing_controller_t(::so_5::outliving_reference_t< ::so_5::environment_t > env, ::so_5::mbox_type_t mbox_type)
Initializing constructor.
Definition pub.hpp:493
const ::so_5::mbox_type_t m_mbox_type
Type of mbox for the demuxer.
Definition pub.hpp:486
::so_5::environment_t & m_env
SObjectizer Environment for that demuxer has been created.
Definition pub.hpp:480
Basic implementation for all kinds of sending_mboxes.
Definition pub.hpp:912
basic_sending_mbox_t(demuxing_controller_iface_shptr_t controller, ::so_5::mbox_id_t id)
Initializing constructor.
Definition pub.hpp:925
demuxing_controller_iface_shptr_t m_controller
Controller to be used.
Definition pub.hpp:914
void set_delivery_filter(const std::type_index &, const delivery_filter_t &, abstract_message_sink_t &) override
Definition pub.hpp:973
void subscribe_event_handler(const std::type_index &, ::so_5::abstract_message_sink_t &) override
Definition pub.hpp:942
void unsubscribe_event_handler(const std::type_index &, abstract_message_sink_t &) noexcept override
Definition pub.hpp:951
void do_deliver_message(message_delivery_mode_t delivery_mode, const std::type_index &msg_type, const message_ref_t &message, unsigned int redirection_deep) override
Definition pub.hpp:959
::so_5::mbox_id_t id() const override
Definition pub.hpp:936
so_5::environment_t & environment() const noexcept override
Definition pub.hpp:992
virtual void drop_delivery_filter(const std::type_index &, abstract_message_sink_t &) noexcept override
Definition pub.hpp:983
const ::so_5::mbox_id_t m_id
ID of the mbox.
Definition pub.hpp:917
Interface for demuxing_controller entity.
Definition pub.hpp:399
virtual::so_5::mbox_type_t mbox_type() const noexcept=0
Get type of sending_mbox for the demuxer.
virtual void consumer_destroyed(consumer_numeric_id_t id) noexcept=0
Notification for destruction of a particular consumer.
virtual::so_5::environment_t & environment() const noexcept=0
Get a reference to SObjectizer Environment for that demuxer has been created.
virtual void do_deliver_message(message_delivery_mode_t delivery_mode, const std::type_index &msg_type, const message_ref_t &message, unsigned int redirection_deep)=0
Delivery of a message.
virtual ::so_5::mbox_t acquire_receiving_mbox_for(consumer_numeric_id_t id, const std::type_index &msg_type)=0
Create a receiving mbox for a consumer.
bool has_parent_factory() const noexcept
Does parent's type factory exists?
Definition pub.hpp:140
const std::type_index & self_type() const noexcept
Getter of the type for that this upcaster object has been created.
Definition pub.hpp:130
std::type_index m_self_type
Type of the message for that this upcaster has been created.
Definition pub.hpp:109
message_upcaster_t parent_upcaster(message_mutability_t mutability) const
Getter for the parent's type upcaster.
Definition pub.hpp:151
message_upcaster_t(std::type_index self_type, upcaster_factory_t parent_factory)
Initializing constructor.
Definition pub.hpp:119
upcaster_factory_t m_parent_factory
Pointer to parent's type upcaster factory.
Definition pub.hpp:115
multi_consumer_demuxing_controller_t(::so_5::outliving_reference_t< ::so_5::environment_t > env)
Initializing constructor.
Definition pub.hpp:630
so_5::mbox_t acquire_receiving_mbox_for(consumer_numeric_id_t id, const std::type_index &msg_type) override
Create a receiving mbox for a consumer.
Definition pub.hpp:637
void consumer_destroyed(consumer_numeric_id_t id) noexcept override
Notification for destruction of a particular consumer.
Definition pub.hpp:659
void do_deliver_message(::so_5::message_delivery_mode_t delivery_mode, const std::type_index &msg_type, const ::so_5::message_ref_t &message, unsigned int redirection_deep) override
Definition pub.hpp:667
multi_consumer_sending_mbox_t(demuxing_controller_iface_shptr_t controller, ::so_5::mbox_id_t id)
Initializing constructor.
Definition pub.hpp:1008
Type to be the actual base class of all hierarchies.
Definition pub.hpp:173
upcaster_factory_t m_factory
The top-level upcaster-factory for the current hierarchy.
Definition pub.hpp:179
void so_set_message_upcaster_factory(upcaster_factory_t factory) noexcept
Setter for the upcaster-factory.
Definition pub.hpp:194
upcaster_factory_t so_message_upcaster_factory() const noexcept
Getter for the stored upcaster-factory.
Definition pub.hpp:184
void consumer_destroyed(consumer_numeric_id_t id) noexcept override
Notification for destruction of a particular consumer.
Definition pub.hpp:781
void do_deliver_message(message_delivery_mode_t delivery_mode, const std::type_index &, const message_ref_t &message, unsigned int redirection_deep) override
Delivery of a message.
Definition pub.hpp:789
so_5::mbox_t acquire_receiving_mbox_for(consumer_numeric_id_t id, const std::type_index &msg_type) override
Create a receiving mbox for a consumer.
Definition pub.hpp:758
single_consumer_demuxing_controller_t(::so_5::outliving_reference_t< ::so_5::environment_t > env)
Initializing constructor.
Definition pub.hpp:751
std::optional< single_dest_info_t > detect_receiver_for_mutable_msg_or_throw(const root_base_t *root) const
Try to find a single destination for a mutable message.
Definition pub.hpp:848
single_consumer_sending_mbox_t(demuxing_controller_iface_shptr_t controller, ::so_5::mbox_id_t id)
Initializing constructor.
Definition pub.hpp:1043
A special mixin to be used for every derived class in a hierarchy.
Definition pub.hpp:338
node_t(Derived &derived)
Initializing constructor.
Definition pub.hpp:371
static impl::message_upcaster_t so_make_upcaster(message_mutability_t mutability) noexcept
Helper method for obtain message-upcaster object for type Derived.
Definition pub.hpp:350
The base class that starts a separate hierarchy.
Definition pub.hpp:223
static impl::message_upcaster_t so_make_upcaster_root(::so_5::message_mutability_t mutability) noexcept
Method that creates the root upcaster-object.
Definition pub.hpp:234
const int msg_hierarchy_errors
Starting point for errors of msg_hierarchy submodule.
const int rc_mpmc_demuxer_cannot_handler_mutable_msg
An attempt to create receiving mbox for a mutable message.
Definition pub.hpp:64
const int rc_message_is_not_derived_from_root
An attempt to deliver a message that type is not derived from root.
Definition pub.hpp:56
const int rc_no_parent_upcaster
An attempt to get parent upcaster but it isn't exists.
Definition pub.hpp:38
const int rc_more_than_one_subscriber_for_mutable_msg
There are more than one subscriber for a mutable message.
Definition pub.hpp:75
const int rc_signal_cannot_be_delivered
An attempt to deliver signal via msg_hierarchy-related mbox.
Definition pub.hpp:48
constexpr consumer_numeric_id_t invalid_consumer_id
Special value that means that a consumer_id is not valid.
Definition pub.hpp:390
constexpr ::so_5::mbox_type_t multi_consumer
Indicator that a demuxer with Multi-Producer/Multi-Consumer mboxes has to be created.
Definition pub.hpp:1600
constexpr ::so_5::mbox_type_t single_consumer
Indicator that a demuxer with Multi-Producer/Single-Consumer mboxes has to be created.
Definition pub.hpp:1607
Ranges for error codes of each submodules.
Definition details.hpp:13
Helper type to be used as mixin for actual demuxing controllers.
Definition pub.hpp:541
void do_delivery_procedure_for_immutable_message(::so_5::message_delivery_mode_t delivery_mode, const ::so_5::message_ref_t &message, unsigned int redirection_deep, const root_base_t *root)
Perform delivery of the message.
Definition pub.hpp:560
consumers_map_t m_consumers_with_mboxes
Map of all consumers.
Definition pub.hpp:552
Metafunction for checking presence of so_make_upcaster method.
Definition pub.hpp:257
Information about a single destination for a mutable message.
Definition pub.hpp:714
single_dest_info_t(so_5::mbox_t dest_mbox, std::type_index subscription_type)
Initializing constructor.
Definition pub.hpp:722
std::type_index m_subscription_type
Subscription type to be used for delivery.
Definition pub.hpp:719
so_5::mbox_t m_dest_mbox
Mbox to be used for delivery.
Definition pub.hpp:716