1 /*
2 	SObjectizer 5.
3 */
4 
5 /*!
6 	\file
7 	\brief A base class for the agent messages definition.
8 */
9 
10 #pragma once
11 
12 #include <so_5/declspec.hpp>
13 #include <so_5/exception.hpp>
14 #include <so_5/atomic_refcounted.hpp>
15 #include <so_5/types.hpp>
16 
17 #include <so_5/agent_ref_fwd.hpp>
18 
19 #include <type_traits>
20 #include <typeindex>
21 #include <functional>
22 #include <future>
23 #include <atomic>
24 
25 namespace so_5
26 {
27 
28 //
29 // message_t
30 //
31 
32 //! A base class for agent messages.
33 /*!
34  * All messages for agents must be derived from this class.
35  *
36  * \attention This class should be used for all messages which
37  * have an actual message data. For signals (messages without any data)
38  * a signal_t class should be used as a base class.
39  *
40  * \note
41  * Class message_t is derived from atomic_refcounted_t.
42  * But atomic_refcounted_t is not Copyable or Movable class.
43  * It means that copy/move constructors and operators for message_t
44  * have no influence on the reference counter inside message_t.
45  */
46 class SO_5_TYPE message_t : public atomic_refcounted_t
47 	{
48 		friend class impl::internal_message_iface_t;
49 	public:
50 		//! A short typedef for kind of message.
51 		/*!
52 		 * \since
53 		 * v.5.5.23
54 		 */
55 		using kind_t = ::so_5::message_kind_t;
56 
57 		message_t();
58 		message_t( const message_t & other );
59 		message_t( message_t && other );
60 
61 		message_t &
62 		operator=( const message_t & other );
63 		message_t &
64 		operator=( message_t && other );
65 
66 		virtual ~message_t() noexcept = default;
67 
68 		/*!
69 		 * \brief Helper method for safe get of message mutability flag.
70 		 *
71 		 * Use this method instead of direct call to so5_message_mutability()
72 		 * because \a what will be nullptr for signals.
73 		 */
74 		friend message_mutability_t
message_mutability(const intrusive_ptr_t<message_t> & what)75 		message_mutability( const intrusive_ptr_t<message_t> & what ) noexcept
76 			{
77 				message_mutability_t r = message_mutability_t::immutable_message;
78 				if( what )
79 					r = what->so5_message_mutability();
80 				return r;
81 			}
82 
83 		/*!
84 		 * \brief Helper method for get message mutability flag.
85 		 */
86 		friend message_mutability_t
message_mutability(const message_t & what)87 		message_mutability( const message_t & what ) noexcept
88 			{
89 				return what.so5_message_mutability();
90 			}
91 
92 		/*!
93 		 * \brief Helper method for safe change message mutability flag.
94 		 *
95 		 * Use this method instead of direct call to so5_change_mutability()
96 		 * because \a what will be nullptr for signals.
97 		 *
98 		 * \note
99 		 * This is a very dangerous operation. Don't do it by yourselt.
100 		 * See message_t::so5_change_mutability() for more details.
101 		 *
102 		 * \attention
103 		 * This function can throw.
104 		 * For example underlying message object can prohibit changing
105 		 * of message mutability.
106 		 */
107 		friend void
change_message_mutability(intrusive_ptr_t<message_t> & what,message_mutability_t mutability)108 		change_message_mutability(
109 			//! Message instance to be modified if it is not a signal.
110 			intrusive_ptr_t< message_t> & what,
111 			//! New mutability flag for the message.
112 			message_mutability_t mutability )
113 			{
114 				if( what )
115 					what->so5_change_mutability( mutability );
116 			}
117 
118 		/*!
119 		 * \brief Helper method for change message mutability flag.
120 		 *
121 		 * \note
122 		 * This is a very dangerous operation. Don't do it by yourselt.
123 		 * See message_t::so5_change_mutability() for more details.
124 		 *
125 		 * \attention
126 		 * This function can throw.
127 		 * For example underlying message object can prohibit changing
128 		 * of message mutability.
129 		 */
130 		friend void
change_message_mutability(message_t & what,message_mutability_t mutability)131 		change_message_mutability(
132 			//! Message instance to be modified.
133 			message_t & what,
134 			//! New mutability flag for the message.
135 			message_mutability_t mutability )
136 			{
137 				what.so5_change_mutability( mutability );
138 			}
139 
140 		/*!
141 		 * \brief Helper method for quering kind of the message.
142 		 *
143 		 * This helper function is necessary because it correctly
144 		 * handles case when message is a signal. In that case pointer
145 		 * to message instance will be null.
146 		 *
147 		 * \note
148 		 * This function is part of internal implementation of SObjectizer.
149 		 * Don't use it directly. It can be a subject of changes in some
150 		 * future versions.
151 		 *
152 		 * \since
153 		 * v.5.5.23
154 		 */
155 		friend message_kind_t
message_kind(const so_5::intrusive_ptr_t<message_t> & what)156 		message_kind(
157 			const so_5::intrusive_ptr_t< message_t > & what )
158 			{
159 				if( what )
160 					return what->so5_message_kind();
161 				else
162 					return message_kind_t::signal;
163 			}
164 
165 		/*!
166 		 * \brief Helper method for quering kind of the message.
167 		 *
168 		 * \note
169 		 * This function is part of internal implementation of SObjectizer.
170 		 * Don't use it directly. It can be a subject of changes in some
171 		 * future versions.
172 		 *
173 		 * \since
174 		 * v.5.5.23
175 		 */
176 		friend message_kind_t
message_kind(const message_t & what)177 		message_kind(
178 			const message_t & what )
179 			{
180 				return what.so5_message_kind();
181 			}
182 
183 	private :
184 		/*!
185 		 * \brief Is message mutable or immutable?
186 		 *
187 		 * By default the message is immutable.
188 		 * \since
189 		 * v.5.5.19
190 		 */
191 		message_mutability_t m_mutability;
192 
193 		/*!
194 		 * \brief Get message mutability flag.
195 		 *
196 		 * \note
197 		 * This method is intended to be used by SObjectizer and
198 		 * low-level SObjectizer extension. Because of that it is not
199 		 * guaranteed that this method is part of stable SObjectizer API.
200 		 * It can be changed or even removed in any future versions
201 		 * of SObjectizer.
202 		 *
203 		 * \note
204 		 * This is a virual method because its behavious must be changed in
205 		 * msg_service_request_t.
206 		 *
207 		 * \since
208 		 * v.5.5.19
209 		 */
210 		virtual message_mutability_t
so5_message_mutability() const211 		so5_message_mutability() const noexcept { return m_mutability; }
212 
213 		/*!
214 		 * \brief Change message mutabilty flag.
215 		 *
216 		 * \attention
217 		 * Changing mutability from message_mutability_t::immutable_message
218 		 * to message_mutability_t::mutable_message is a very bad idea.
219 		 * Please don't do this until you are know what you are doing.
220 		 *
221 		 * \note
222 		 * This method is intended to be used by SObjectizer and
223 		 * low-level SObjectizer extension. Because of that it is not
224 		 * guaranteed that this method is part of stable SObjectizer API.
225 		 * It can be changed or even removed in any future versions
226 		 * of SObjectizer.
227 		 *
228 		 * \note
229 		 * This is a virual method because its behavious must be changed in
230 		 * msg_service_request_t.
231 		 *
232 		 * \attention
233 		 * This function can throw.
234 		 * For example a derived class can prohibit changing
235 		 * of message mutability.
236 		 *
237 		 * \since
238 		 * v.5.5.19
239 		 */
240 		virtual void
so5_change_mutability(message_mutability_t mutability)241 		so5_change_mutability(
242 			//! New mutability flag for
243 			message_mutability_t mutability )
244 			{
245 				m_mutability = mutability;
246 			}
247 
248 		/*!
249 		 * \brief Detect the kind of the message.
250 		 *
251 		 * \note
252 		 * This method is intended to be used by SObjectizer and
253 		 * low-level SObjectizer extension. Because of that it is not
254 		 * guaranteed that this method is part of stable SObjectizer API.
255 		 * It can be changed or even removed in any future versions
256 		 * of SObjectizer.
257 		 *
258 		 * \since
259 		 * v.5.5.23
260 		 */
261 		virtual kind_t
so5_message_kind() const262 		so5_message_kind() const noexcept
263 			{
264 				return kind_t::classical_message;
265 			}
266 	};
267 
268 //
269 // message_ref_t
270 //
271 //! A smart reference to the message.
272 /*!
273  * \note Defined as typedef since v.5.2.0
274  */
275 using message_ref_t = intrusive_ptr_t< message_t >;
276 
277 //
278 // signal_t
279 //
280 //! A base class for agent signals.
281 /*!
282  * \since
283  * v.5.2.0
284  *
285  * All signals (messages without any data) for agents should be
286  * derived from this class.
287  */
288 class SO_5_TYPE signal_t
289 	:	public message_t
290 {
291 	private :
292 		// Note: clang-3.9 requires this on Windows platform.
293 		signal_t( const signal_t & ) = delete;
294 		signal_t( signal_t && ) = delete;
295 		signal_t & operator=( const signal_t & ) = delete;
296 		signal_t & operator=( signal_t && ) = delete;
297 
298 		/*!
299 		 * Private constructor to disable creation of instances of
300 		 * derived classes.
301 		 */
302 		signal_t() = default;
303 
304 		// Note: this method has no sence in v.5.5, becasue instances
305 		// of that class are not created at all.
306 		// But that can be changed in v.5.6.0.
307 		kind_t
so5_message_kind() const308 		so5_message_kind() const noexcept override
309 			{
310 				return kind_t::classical_message;
311 			}
312 
313 	public :
314 		~signal_t() noexcept override = default;
315 };
316 
317 //
318 // user_type_message_t
319 //
320 /*!
321  * \brief Template class for representing object of user type as a message.
322  *
323  * \tparam T type of actual message. This type must have move- or copy
324  * constructor.
325  *
326  * \since
327  * v.5.5.9
328  */
329 template< typename T >
330 struct user_type_message_t : public message_t
331 {
332 	//! Instance of user message.
333 	/*!
334 	 * \note
335 	 * Since v.5.5.19 it is not a const object anymore.
336 	 */
337 	T m_payload;
338 
339 	//! Initializing constructor.
340 	template< typename... Args >
user_type_message_tso_5::user_type_message_t341 	user_type_message_t( Args &&... args )
342 		:	m_payload{ std::forward< Args >( args )... }
343 		{}
344 
345 	//! Initialization from const T object.
user_type_message_tso_5::user_type_message_t346 	user_type_message_t( const T & o )
347 		:	m_payload{ o }
348 		{}
349 
350 	//! Initialization from non-const T object.
user_type_message_tso_5::user_type_message_t351 	user_type_message_t( T & o )
352 		:	m_payload{ o }
353 		{}
354 
355 	//! Initialization from temporary T object.
user_type_message_tso_5::user_type_message_t356 	user_type_message_t( T && o )
357 		:	m_payload{ std::move(o) }
358 		{}
359 
360 private :
361 	kind_t
so5_message_kindso_5::user_type_message_t362 	so5_message_kind() const noexcept override
363 		{
364 			return kind_t::user_type_message;
365 		}
366 };
367 
368 //
369 // immutable_msg
370 //
371 /*!
372  * \brief A special marker for immutable message.
373  *
374  * This marker tells that message can be sent to several receivers and
375  * nobody can change the message content.
376  *
377  * \tparam M type of the message.
378  *
379  * \since
380  * v.5.5.19
381  */
382 template< typename M >
383 struct immutable_msg final {};
384 
385 //
386 // mutable_msg
387 //
388 /*!
389  * \brief A special marker for mutable message.
390  *
391  * This marker tells that message can be sent only for one receiver.
392  * And that receiver will get an exclusive access to the message content.
393  * It means that receiver can change message's content.
394  *
395  * \tparam M type of the message.
396  *
397  * \since
398  * v.5.5.19
399  */
400 template< typename M >
401 struct mutable_msg final {};
402 
403 namespace details {
404 
405 //
406 // message_mutability_traits
407 //
408 /*!
409  * \brief Detector of message type traits in dependency of message immutability
410  * or mutability.
411  *
412  * \since
413  * v.5.5.19
414  */
415 template< typename T >
416 struct message_mutability_traits
417 	{
418 		using payload_type = typename std::decay<T>::type;
419 		using subscription_type = payload_type;
420 		using mhood_param_type = payload_type;
421 
422 		static const constexpr message_mutability_t mutability =
423 				message_mutability_t::immutable_message;
424 	};
425 
426 template< typename T >
427 struct message_mutability_traits< immutable_msg<T> >
428 	{
429 		using payload_type = T;
430 		using subscription_type = T;
431 		using mhood_param_type = T;
432 
433 		static const constexpr message_mutability_t mutability =
434 				message_mutability_t::immutable_message;
435 	};
436 
437 template< typename T >
438 struct message_mutability_traits< mutable_msg<T> >
439 	{
440 		using payload_type = T;
441 		using subscription_type = mutable_msg<T>;
442 		using mhood_param_type = mutable_msg<T>;
443 
444 		static const constexpr message_mutability_t mutability =
445 				message_mutability_t::mutable_message;
446 	};
447 
448 } /* namespace details */
449 
450 //
451 // is_user_type_message
452 //
453 /*!
454  * \since
455  * v.5.5.9
456  *
457  * \brief A helper for detection presence of message of user type.
458  *
459  * \tparam M type to test.
460  */
461 template< typename M >
462 struct is_user_type_message
463 	{
464 		enum { value = false };
465 	};
466 
467 template< typename M >
468 struct is_user_type_message< user_type_message_t< M > >
469 	{
470 		enum { value = true };
471 	};
472 
473 //
474 // is_signal
475 //
476 /*!
477  * \since
478  * v.5.5.4
479  *
480  * \brief A helper class for checking that message is a signal.
481  */
482 template< class T >
483 struct is_signal
484 	{
485 		enum { value = std::is_base_of<
486 				signal_t,
487 				typename details::message_mutability_traits<T>::payload_type >::value };
488 	};
489 
490 //
491 // is_classical_message
492 //
493 /*!
494  * \since
495  * v.5.5.9
496  *
497  * \brief A helper class for checking that message is a classical message
498  * derived from %message_t class.
499  */
500 template< class T >
501 struct is_classical_message
502 	{
503 		enum { value = std::is_base_of<
504 				message_t,
505 				typename details::message_mutability_traits<T>::payload_type >::value };
506 	};
507 
508 //
509 // is_mutable_message
510 //
511 /*!
512  * \brief A helper class for checking that message is a mutable message.
513  *
514  * \since
515  * v.5.5.19
516  */
517 template< typename T >
518 struct is_mutable_message
519 	{
520 		enum { value = false };
521 	};
522 
523 template< typename T >
524 struct is_mutable_message< mutable_msg<T> >
525 	{
526 		enum { value = true };
527 	};
528 
529 //
530 // ensure_not_signal
531 //
532 /*!
533  * \since
534  * v.5.2.0
535  *
536  * \brief A special compile-time checker to guarantee that the message
537  * class is not a signal class.
538  */
539 template< class Msg >
540 void
ensure_not_signal()541 ensure_not_signal()
542 {
543 	static_assert( !is_signal< Msg >::value,
544 			"message class must be derived from the message_t" );
545 }
546 
547 //
548 // ensure_message_with_actual_data
549 //
550 /*!
551  * \since
552  * v.5.2.0
553  *
554  * \brief A special checker to guarantee that the message is an instance
555  * of the message_t (not signal_t) and has a not-null pointer
556  * to the message data.
557  *
558  * \note A check for the inheritance from the message_t is done at compile-time.
559  *
560  * \tparam Msg message type to be checked.
561  */
562 template< class Msg >
563 void
ensure_message_with_actual_data(const Msg * m)564 ensure_message_with_actual_data( const Msg * m )
565 {
566 	ensure_not_signal< Msg >();
567 
568 	if( !m )
569 		throw so_5::exception_t(
570 				"an attempt to send a message via nullptr",
571 				so_5::rc_null_message_data );
572 }
573 
574 //
575 // ensure_not_mutable_signal
576 //
577 /*!
578  * \brief A special compile-time checker to guarantee that S is not a
579  * mutable signal.
580  *
581  * This check is intended to prevent usage of mutable_msg<S> where S is
582  * a signal type.
583  *
584  * \since
585  * v.5.5.19
586  */
587 template< class S >
588 void
ensure_not_mutable_signal()589 ensure_not_mutable_signal()
590 {
591 	static_assert( !is_signal<S>::value ||
592 			message_mutability_t::immutable_message ==
593 					details::message_mutability_traits<S>::mutability,
594 			"usage of mutable_msg<S> where S is a signal is prohibited" );
595 }
596 
597 //
598 // ensure_signal
599 //
600 /*!
601  * \since
602  * v.5.2.0
603  *
604  * \brief A special compile-time checker to guarantee that the Msg is derived
605  * from the signal_t.
606  *
607  * \tparam Msg signal type to be checked.
608  */
609 template< class Msg >
610 void
ensure_signal()611 ensure_signal()
612 {
613 	static_assert( is_signal< Msg >::value,
614 			"expected a type derived from the signal_t" );
615 
616 	// Added in v.5.5.19.
617 	// Msg must not be a mutable_msg<S>.
618 	ensure_not_mutable_signal<Msg>();
619 }
620 
621 //
622 // ensure_classical_message
623 //
624 /*!
625  * \since
626  * v.5.5.9
627  *
628  * \brief A special compile-time checker to guarantee that Msg is derived from
629  * %message_t.
630  *
631  * \tparam Msg type to be checked.
632  */
633 template< typename Msg >
634 void
ensure_classical_message()635 ensure_classical_message()
636 	{
637 		static_assert( is_classical_message< Msg >::value,
638 				"expected a type derived from the message_t" );
639 	}
640 
641 //
642 // message_payload_type_impl
643 //
644 /*!
645  * \since
646  * v.5.5.9
647  *
648  * \brief Implementation details for %message_payload_type.
649  *
650  * \note This specialization is for cases where T is derived from message_t.
651  * In that case payload_type is the same as envelope_type.
652  */
653 template< typename T, bool is_classical_message >
654 struct message_payload_type_impl
655 	{
656 		//! Mutability traits for this message type.
657 		using mutability_traits = details::message_mutability_traits<T>;
658 
659 		//! Type visible to user.
660 		using payload_type = typename mutability_traits::payload_type;
661 		//! Type for message delivery.
662 		using envelope_type = payload_type;
663 		//! Type to which subscription must be done.
664 		using subscription_type = typename mutability_traits::subscription_type;
665 
666 		//! Is it a signal type or message type.
667 		static constexpr const bool is_signal = ::so_5::is_signal<T>::value;
668 
669 		//! Type ID for subscription.
subscription_type_indexso_5::message_payload_type_impl670 		inline static std::type_index subscription_type_index()
671 			{
672 				// T must not be a mutable_msg<T>.
673 				ensure_not_mutable_signal<T>();
674 
675 				return typeid(subscription_type);
676 			}
677 
678 		//! Helper for extraction of pointer to payload part.
679 		/*!
680 		 * \note This method return non-const pointer because it is
681 		 * necessary for so_5::mhood_t.
682 		 */
683 		inline static payload_type *
extract_payload_ptrso_5::message_payload_type_impl684 		extract_payload_ptr( message_ref_t & msg )
685 			{
686 				return dynamic_cast< payload_type * >( msg.get() );
687 			}
688 
689 		//! Helper for extraction of pointer to envelope part.
690 		/*!
691 		 * The same implementation as for extract_envelope_ptr().
692 		 */
693 		inline static envelope_type *
extract_envelope_ptrso_5::message_payload_type_impl694 		extract_envelope_ptr( message_ref_t & msg )
695 			{
696 				return dynamic_cast< envelope_type * >( msg.get() );
697 			}
698 
699 		//! Helper for getting a const reference to payload part.
700 		inline static payload_type &
payload_referenceso_5::message_payload_type_impl701 		payload_reference( message_t & msg )
702 			{
703 				return dynamic_cast< payload_type & >( msg );
704 			}
705 
706 		//! Helper for getting message mutability flag.
707 		inline static message_mutability_t
mutabilityso_5::message_payload_type_impl708 		mutability()
709 			{
710 				return mutability_traits::mutability;
711 			}
712 	};
713 
714 /*!
715  * \since
716  * v.5.5.9
717  *
718  * \brief Implementation details for %message_payload_type.
719  *
720  * \note This specialization is for cases where T is not derived from message_t.
721  * In that case payload_type is T, but envelope_type is user_type_message_t<T>.
722  */
723 template< typename T >
724 struct message_payload_type_impl< T, false >
725 	{
726 		//! Mutability traits for this message type.
727 		using mutability_traits = details::message_mutability_traits<T>;
728 
729 		//! Type visible to user.
730 		using payload_type = typename mutability_traits::payload_type;
731 		//! Type for message delivery.
732 		using envelope_type = user_type_message_t< payload_type >;
733 		//! Type to which subscription must be done.
734 		using subscription_type = typename mutability_traits::subscription_type;
735 
736 		//! Is it a signal type or message type.
737 		/*!
738 		 * \note
739 		 * User-defined type can't be a signal.
740 		 */
741 		static constexpr const bool is_signal = false;
742 
743 		//! Type ID for subscription.
subscription_type_indexso_5::message_payload_type_impl744 		inline static std::type_index subscription_type_index()
745 			{
746 				return typeid(subscription_type);
747 			}
748 
749 		//! Helper for extraction of pointer to payload part.
750 		/*!
751 		 * \note This method return const pointer because payload is
752 		 * a const object inside user_type_message_t<T> instance.
753 		 */
754 		inline static payload_type *
extract_payload_ptrso_5::message_payload_type_impl755 		extract_payload_ptr( message_ref_t & msg )
756 			{
757 				auto envelope = dynamic_cast< envelope_type * >( msg.get() );
758 				if( !envelope )
759 					SO_5_THROW_EXCEPTION( so_5::rc_unexpected_error,
760 							"nullptr for user_type_message_t<T> instance" );
761 
762 				return &(envelope->m_payload);
763 			}
764 
765 		//! Helper for extraction of pointer to envelope part.
766 		inline static envelope_type *
extract_envelope_ptrso_5::message_payload_type_impl767 		extract_envelope_ptr( message_ref_t & msg )
768 			{
769 				return dynamic_cast< envelope_type * >( msg.get() );
770 			}
771 
772 		//! Helper for getting a const reference to payload part.
773 		inline static payload_type &
payload_referenceso_5::message_payload_type_impl774 		payload_reference( message_t & msg )
775 			{
776 				auto & envelope = dynamic_cast< envelope_type & >( msg );
777 				return envelope.m_payload;
778 			}
779 
780 		//! Helper for getting message mutability flag.
781 		inline static message_mutability_t
mutabilityso_5::message_payload_type_impl782 		mutability()
783 			{
784 				return mutability_traits::mutability;
785 			}
786 	};
787 
788 //
789 // message_payload_type
790 //
791 /*!
792  * \since
793  * v.5.5.9
794  *
795  * \brief A helper class for detection of payload type of message.
796  *
797  * \tparam T type to test.
798  */
799 template< typename T >
800 struct message_payload_type
801 	:	public message_payload_type_impl< T,
802 			is_classical_message<
803 					typename ::so_5::details::message_mutability_traits<T>::payload_type >::value >
804 	{
805 	};
806 
807 template< typename T >
808 struct message_payload_type< user_type_message_t< T > >
809 	:	public message_payload_type_impl< T, false >
810 	{
811 	};
812 
813 namespace details
814 {
815 
816 template< typename Msg >
817 typename std::enable_if<
818 	message_mutability_t::mutable_message ==
819 			::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_t & msg)820 mark_as_mutable_if_necessary( message_t & msg )
821 	{
822 		change_message_mutability( msg, message_mutability_t::mutable_message );
823 	}
824 
825 /*!
826  * \since
827  * v.5.6.0
828  */
829 template< typename Msg >
830 typename std::enable_if<
831 	message_mutability_t::mutable_message ==
832 			::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_ref_t & msg)833 mark_as_mutable_if_necessary( message_ref_t & msg )
834 	{
835 		change_message_mutability( *msg, message_mutability_t::mutable_message );
836 	}
837 
838 template< typename Msg >
839 typename std::enable_if<
840 	message_mutability_t::mutable_message !=
841 			::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_t &)842 mark_as_mutable_if_necessary( message_t & /*msg*/ )
843 	{
844 		// Nothing to do.
845 	}
846 
847 /*!
848  * \since
849  * v.5.6.0
850  */
851 template< typename Msg >
852 typename std::enable_if<
853 	message_mutability_t::mutable_message !=
854 			::so_5::details::message_mutability_traits<Msg>::mutability >::type
mark_as_mutable_if_necessary(message_ref_t &)855 mark_as_mutable_if_necessary( message_ref_t & /*msg*/ )
856 	{
857 		// Nothing to do.
858 	}
859 
860 template< bool is_signal, typename Msg >
861 struct make_message_instance_impl
862 	{
863 		using E = typename message_payload_type< Msg >::envelope_type;
864 
865 		template< typename... Args >
866 		static std::unique_ptr< E >
makeso_5::details::make_message_instance_impl867 		make( Args &&... args )
868 			{
869 				ensure_not_signal< Msg >();
870 
871 				return std::unique_ptr< E >( new E( std::forward< Args >(args)... ) );
872 			}
873 	};
874 
875 template< typename Msg >
876 struct make_message_instance_impl< true, Msg >
877 	{
878 		static std::unique_ptr< Msg >
makeso_5::details::make_message_instance_impl879 		make()
880 			{
881 				ensure_signal< Msg >();
882 
883 				return std::unique_ptr< Msg >();
884 			}
885 	};
886 
887 /*!
888  * \since
889  * v.5.5.4
890  *
891  * \brief A helper for allocate instance of a message.
892  */
893 template< typename Msg, typename... Args >
894 auto
make_message_instance(Args &&...args)895 make_message_instance( Args &&... args )
896 	-> std::unique_ptr< typename message_payload_type< Msg >::envelope_type >
897 	{
898 		return make_message_instance_impl<
899 						is_signal< Msg >::value, Msg
900 				>::make( std::forward< Args >( args )... );
901 	}
902 
903 } /* namespace details */
904 
905 namespace message_limit
906 {
907 
908 struct control_block_t;
909 
910 //
911 // any_unspecified_message
912 //
913 
914 /*!
915  * \brief A special mark to be used for default limits.
916  *
917  * \since
918  * v.5.7.1
919  */
920 class SO_5_TYPE any_unspecified_message final
921 	{
922 		// Instances of that type can't be created.
923 		~any_unspecified_message();
924 		any_unspecified_message();
925 	};
926 
927 namespace impl
928 {
929 
930 class action_msg_tracer_t;
931 
932 } /* namespace impl */
933 
934 /*!
935  * \since
936  * v.5.5.4
937  *
938  * \brief Description of context for overlimit action.
939  */
940 struct overlimit_context_t
941 	{
942 		//! ID of mbox which is used for message delivery.
943 		/*!
944 		 * Added in v.5.5.23 because it is necessary for
945 		 * so_5::enveloped_msg::handling_context_t.
946 		 */
947 		const mbox_id_t m_mbox_id;
948 
949 		//! Receiver of the message or service request.
950 		const agent_t & m_receiver;
951 
952 		//! Control block for message limit.
953 		const control_block_t & m_limit;
954 
955 		//! The current deep of overlimit reaction recursion.
956 		const unsigned int m_reaction_deep;
957 
958 		//! Type of message to be delivered.
959 		const std::type_index & m_msg_type;
960 
961 		//! A message or service request to be delivered.
962 		const message_ref_t & m_message;
963 
964 		/*!
965 		 * \since
966 		 * v.5.5.9
967 		 *
968 		 * \brief An optional pointer to tracer object for
969 		 * message delivery tracing.
970 		 *
971 		 * \note Value nullptr means that message delivery tracing
972 		 * is not used.
973 		 */
974 		const impl::action_msg_tracer_t * m_msg_tracer;
975 
976 		//! Initializing constructor.
977 		inline
overlimit_context_tso_5::message_limit::overlimit_context_t978 		overlimit_context_t(
979 			mbox_id_t mbox_id,
980 			const agent_t & receiver,
981 			const control_block_t & limit,
982 			unsigned int reaction_deep,
983 			const std::type_index & msg_type,
984 			const message_ref_t & message,
985 			const impl::action_msg_tracer_t * msg_tracer )
986 			:	m_mbox_id( mbox_id )
987 			,	m_receiver( receiver )
988 			,	m_limit( limit )
989 			,	m_reaction_deep( reaction_deep )
990 			,	m_msg_type( msg_type )
991 			,	m_message( message )
992 			,	m_msg_tracer{ msg_tracer }
993 			{}
994 	};
995 
996 //
997 // action_t
998 //
999 /*!
1000  * \since
1001  * v.5.5.4
1002  *
1003  * \brief A type for reaction of message overlimit.
1004  */
1005 using action_t = std::function< void(const overlimit_context_t&) >;
1006 
1007 //
1008 // control_block_t
1009 //
1010 /*!
1011  * \since
1012  * v.5.5.4
1013  *
1014  * \brief A control block for one message limit.
1015  */
1016 struct control_block_t
1017 	{
1018 		//! Limit value.
1019 		unsigned int m_limit;
1020 
1021 		//! The current count of the messages of that type.
1022 		mutable std::atomic_uint m_count;
1023 
1024 		//! Limit overflow reaction.
1025 		action_t m_action;
1026 
1027 		//! Initializing constructor.
control_block_tso_5::message_limit::control_block_t1028 		control_block_t(
1029 			unsigned int limit,
1030 			action_t action )
1031 			:	m_limit( limit )
1032 			,	m_action( std::move( action ) )
1033 			{
1034 				m_count = 0;
1035 			}
1036 
1037 		//! Copy constructor.
control_block_tso_5::message_limit::control_block_t1038 		control_block_t(
1039 			const control_block_t & o )
1040 			:	m_limit( o.m_limit )
1041 			,	m_action( o.m_action )
1042 			{
1043 				m_count.store(
1044 						o.m_count.load( std::memory_order_acquire ),
1045 						std::memory_order_release );
1046 			}
1047 
1048 		//! Copy operator.
1049 		control_block_t &
operator =so_5::message_limit::control_block_t1050 		operator=( const control_block_t & o )
1051 			{
1052 				m_limit = o.m_limit;
1053 				m_count.store(
1054 						o.m_count.load( std::memory_order_acquire ),
1055 						std::memory_order_release );
1056 				m_action = o.m_action;
1057 
1058 				return *this;
1059 			}
1060 
1061 		//! A special indicator about absence of control_block.
1062 		inline static const control_block_t *
noneso_5::message_limit::control_block_t1063 		none() { return nullptr; }
1064 
1065 		//! A safe decrement of message count with respect to absence of limit
1066 		//! for a message.
1067 		inline static void
decrementso_5::message_limit::control_block_t1068 		decrement( const control_block_t * limit )
1069 			{
1070 				if( limit )
1071 					--(limit->m_count);
1072 			}
1073 	};
1074 
1075 } /* namespace message_limit */
1076 
1077 } /* namespace so_5 */
1078 
1079