1 /*
2 	SObjectizer 5.
3 */
4 
5 /*!
6 	\file
7 	\brief Functions for creating and binding to the active group dispatcher.
8 */
9 
10 #pragma once
11 
12 #include <so_5/declspec.hpp>
13 
14 #include <so_5/disp_binder.hpp>
15 #include <so_5/nonempty_name.hpp>
16 
17 #include <so_5/disp/mpsc_queue_traits/pub.hpp>
18 
19 #include <so_5/disp/reuse/work_thread_activity_tracking.hpp>
20 
21 #include <string>
22 #include <string_view>
23 
24 namespace so_5
25 {
26 
27 namespace disp
28 {
29 
30 namespace active_group
31 {
32 
33 /*!
34  * \brief Alias for namespace with traits of event queue.
35  *
36  * \since
37  * v.5.5.10
38  */
39 namespace queue_traits = so_5::disp::mpsc_queue_traits;
40 
41 //
42 // disp_params_t
43 //
44 /*!
45  * \brief Parameters for active group dispatcher.
46  *
47  * \since
48  * v.5.5.10
49  */
50 class disp_params_t
51 	:	public so_5::disp::reuse::work_thread_activity_tracking_flag_mixin_t< disp_params_t >
52 	{
53 		using activity_tracking_mixin_t = so_5::disp::reuse::
54 				work_thread_activity_tracking_flag_mixin_t< disp_params_t >;
55 
56 	public :
57 		//! Default constructor.
58 		disp_params_t() = default;
59 
60 		friend inline void
swap(disp_params_t & a,disp_params_t & b)61 		swap( disp_params_t & a, disp_params_t & b ) noexcept
62 			{
63 				swap(
64 						static_cast< activity_tracking_mixin_t & >(a),
65 						static_cast< activity_tracking_mixin_t & >(b) );
66 				swap( a.m_queue_params, b.m_queue_params );
67 			}
68 
69 		//! Setter for queue parameters.
70 		disp_params_t &
set_queue_params(queue_traits::queue_params_t p)71 		set_queue_params( queue_traits::queue_params_t p )
72 			{
73 				m_queue_params = std::move(p);
74 				return *this;
75 			}
76 
77 		//! Tuner for queue parameters.
78 		/*!
79 		 * Accepts lambda-function or functional object which tunes
80 		 * queue parameters.
81 			\code
82 			so_5::disp::active_group::make_dispatcher( env,
83 				"my_active_group_disp",
84 				so_5::disp::active_group::disp_params_t{}.tune_queue_params(
85 					[]( so_5::disp::active_group::queue_traits::queue_params_t & p ) {
86 						p.lock_factory( so_5::disp::active_group::queue_traits::simple_lock_factory() );
87 					} ) );
88 			\endcode
89 		 */
90 		template< typename L >
91 		disp_params_t &
tune_queue_params(L tunner)92 		tune_queue_params( L tunner )
93 			{
94 				tunner( m_queue_params );
95 				return *this;
96 			}
97 
98 		//! Getter for queue parameters.
99 		const queue_traits::queue_params_t &
queue_params() const100 		queue_params() const
101 			{
102 				return m_queue_params;
103 			}
104 
105 	private :
106 		//! Queue parameters.
107 		queue_traits::queue_params_t m_queue_params;
108 	};
109 
110 namespace impl {
111 
112 class actual_dispatcher_iface_t;
113 
114 //
115 // basic_dispatcher_iface_t
116 //
117 /*!
118  * \brief The very basic interface of %active_group dispatcher.
119  *
120  * This class contains a minimum that is necessary for implementation
121  * of dispatcher_handle class.
122  *
123  * \since
124  * v.5.6.0
125  */
126 class basic_dispatcher_iface_t
127 	:	public std::enable_shared_from_this<actual_dispatcher_iface_t>
128 	{
129 	public :
130 		virtual ~basic_dispatcher_iface_t() noexcept = default;
131 
132 		[[nodiscard]]
133 		virtual disp_binder_shptr_t
134 		binder( nonempty_name_t group_name ) = 0;
135 	};
136 
137 using basic_dispatcher_iface_shptr_t =
138 		std::shared_ptr< basic_dispatcher_iface_t >;
139 
140 class dispatcher_handle_maker_t;
141 
142 } /* namespace impl */
143 
144 //
145 // dispatcher_handle_t
146 //
147 
148 /*!
149  * \since
150  * v.5.6.0
151  *
152  * \brief A handle for %active_group dispatcher.
153  */
154 class [[nodiscard]] dispatcher_handle_t
155 	{
156 		friend class impl::dispatcher_handle_maker_t;
157 
158 		//! A reference to actual implementation of a dispatcher.
159 		impl::basic_dispatcher_iface_shptr_t m_dispatcher;
160 
dispatcher_handle_t(impl::basic_dispatcher_iface_shptr_t dispatcher)161 		dispatcher_handle_t(
162 			impl::basic_dispatcher_iface_shptr_t dispatcher ) noexcept
163 			:	m_dispatcher{ std::move(dispatcher) }
164 			{}
165 
166 		//! Is this handle empty?
167 		bool
empty() const168 		empty() const noexcept { return !m_dispatcher; }
169 
170 	public :
171 		dispatcher_handle_t() noexcept = default;
172 
173 		//! Get a binder for that dispatcher.
174 		/*!
175 		 * \attention
176 		 * An attempt to call this method on empty handle is UB.
177 		 */
178 		[[nodiscard]]
179 		disp_binder_shptr_t
binder(nonempty_name_t group_name) const180 		binder(
181 			//! Name of group for a new agent.
182 			nonempty_name_t group_name ) const
183 			{
184 				return m_dispatcher->binder( std::move(group_name) );
185 			}
186 
187 		//! Is this handle empty?
operator bool() const188 		operator bool() const noexcept { return empty(); }
189 
190 		//! Does this handle contain a reference to dispatcher?
191 		bool
operator !() const192 		operator!() const noexcept { return !empty(); }
193 
194 		//! Drop the content of handle.
195 		void
reset()196 		reset() noexcept { m_dispatcher.reset(); }
197 	};
198 
199 /*!
200  * \brief Create an instance of %active_group dispatcher.
201  *
202  * \par Usage sample
203 \code
204 auto disp = so_5::disp::active_group::make_dispatcher(
205 	env,
206 	"request_handler",
207 	// Additional params with specific options for queue's traits.
208 	so_5::disp::active_group::disp_params_t{}.tune_queue_params(
209 		[]( so_5::disp::active_group::queue_traits::queue_params_t & p ) {
210 			p.lock_factory( so_5::disp::active_obj::queue_traits::simple_lock_factory() );
211 		} ) );
212 auto coop = env.make_coop(
213 	// The main dispatcher for that coop will be
214 	// this instance of active_group dispatcher.
215 	disp.binder( "request_handler" ) );
216 \endcode
217  *
218  * \since
219  * v.5.6.0
220  */
221 SO_5_FUNC dispatcher_handle_t
222 make_dispatcher(
223 	//! SObjectizer Environment to work in.
224 	so_5::environment_t & env,
225 	//! Value for creating names of data sources for
226 	//! run-time monitoring.
227 	const std::string_view data_sources_name_base,
228 	//! Parameters for dispatcher.
229 	disp_params_t params );
230 
231 /*!
232  * \brief Create an instance of %active_group dispatcher.
233  *
234  * \par Usage sample
235 \code
236 auto disp = so_5::disp::active_group::make_dispatcher(
237 	env,
238 	"long_req_handlers" );
239 
240 auto coop = env.make_coop(
241 	// The main dispatcher for that coop will be
242 	// this instance of active_group dispatcher.
243 	disp.binder( "passive_objects" ) );
244 \endcode
245  *
246  * \since
247  * v.5.6.0
248  */
249 inline dispatcher_handle_t
make_dispatcher(so_5::environment_t & env,const std::string_view data_sources_name_base)250 make_dispatcher(
251 	//! SObjectizer Environment to work in.
252 	so_5::environment_t & env,
253 	//! Value for creating names of data sources for
254 	//! run-time monitoring.
255 	const std::string_view data_sources_name_base )
256 	{
257 		return make_dispatcher( env, data_sources_name_base, disp_params_t{} );
258 	}
259 
260 /*!
261  * \brief Create an instance of %active_group dispatcher.
262  *
263  * \par Usage sample
264 \code
265 auto disp = so_5::disp::active_group::make_dispatcher( env );
266 
267 auto coop = env.make_coop(
268 	// The main dispatcher for that coop will be
269 	// this instance of active_group dispatcher.
270 	disp.binder( "passive_objects" ) );
271 \endcode
272  *
273  * \since
274  * v.5.6.0
275  */
276 inline dispatcher_handle_t
make_dispatcher(so_5::environment_t & env)277 make_dispatcher(
278 	//! SObjectizer Environment to work in.
279 	so_5::environment_t & env )
280 	{
281 		return make_dispatcher( env, std::string_view{} );
282 	}
283 
284 } /* namespace active_group */
285 
286 } /* namespace disp */
287 
288 } /* namespace so_5 */
289 
290