1//! @file action.hpp
2//! @author ryftchen
3//! @brief The declarations (action) in the application module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2025 ryftchen. All rights reserved.
6
7#pragma once
8
9#ifndef _PRECOMPILED_HEADER
10#include <coroutine>
11#else
12#include "application/pch/precompiled_header.hpp"
13#endif // _PRECOMPILED_HEADER
14
15#include "application/example/include/register_algorithm.hpp"
16#include "application/example/include/register_data_structure.hpp"
17#include "application/example/include/register_design_pattern.hpp"
18#include "application/example/include/register_numeric.hpp"
19
20//! @brief The application module.
21namespace application // NOLINT(modernize-concat-nested-namespaces)
22{
23//! @brief Applied-action-related functions in the application module.
24namespace action
25{
26//! @brief Awaitable coroutine.
27class Awaitable final
28{
29public:
30 // NOLINTBEGIN(readability-identifier-naming)
31 //! @brief Promise type for use in coroutines.
32 struct promise_type
33 {
34 //! @brief Get the return object for the coroutine.
35 //! @return awaitable instance
36 Awaitable get_return_object() { return Awaitable{std::coroutine_handle<promise_type>::from_promise(p&: *this)}; }
37 //! @brief Initial suspend point of the coroutine.
38 //! @return std::suspend_never object indicating that the coroutine should not be suspended initially
39 static std::suspend_never initial_suspend() noexcept { return {}; }
40 //! @brief Final suspend point of the coroutine.
41 //! @return std::suspend_always object indicating that the coroutine should be suspended finally
42 static std::suspend_always final_suspend() noexcept { return {}; }
43 //! @brief Complete the coroutine without returning a value.
44 static void return_void() noexcept {}
45 //! @brief Handle exceptions thrown within the coroutine.
46 static void unhandled_exception() { std::rethrow_exception(std::current_exception()); }
47 };
48 // NOLINTEND(readability-identifier-naming)
49
50 //! @brief Construct a new Awaitable object.
51 //! @param handle - coroutine handle
52 explicit Awaitable(const std::coroutine_handle<promise_type>& handle);
53 //! @brief Destroy the Awaitable object.
54 ~Awaitable();
55 //! @brief Construct a new Awaitable object.
56 Awaitable(const Awaitable&) = delete;
57 //! @brief Construct a new Awaitable object.
58 Awaitable(Awaitable&&) = delete;
59 //! @brief The operator (=) overloading of Awaitable class.
60 //! @return reference of the Awaitable object
61 Awaitable& operator=(const Awaitable&) = delete;
62 //! @brief The operator (=) overloading of Awaitable class.
63 //! @return reference of the Awaitable object
64 Awaitable& operator=(Awaitable&&) = delete;
65
66 //! @brief Resume the execution of the coroutine if it is suspended.
67 void resume() const;
68 //! @brief Check whether the coroutine has been completed.
69 //! @return be done or not
70 [[nodiscard]] bool done() const;
71
72private:
73 //! @brief Coroutine handle.
74 std::coroutine_handle<promise_type> handle;
75 //! @brief Flag to ensure only one instance is active.
76 static std::atomic_bool active;
77};
78
79//! @brief Alias for the type information.
80//! @tparam UDT - type of user defined data
81template <typename UDT>
82using TypeInfo = utility::reflection::TypeInfo<UDT>;
83//! @brief Get the name field directly for sub-cli related registrations.
84//! @tparam MappedCLI - type of sub-cli or sub-cli's category
85//! @return name field
86template <typename MappedCLI>
87consteval std::string_view name()
88{
89 return TypeInfo<MappedCLI>::name;
90}
91//! @brief Get the alias attribute directly for sub-cli related registrations.
92//! @tparam Meth - type of sub-cli's category
93//! @return alias attribute
94template <typename Meth>
95requires std::is_same_v<Meth, reg_algo::MatchMethod> || std::is_same_v<Meth, reg_algo::NotationMethod>
96 || std::is_same_v<Meth, reg_algo::OptimalMethod> || std::is_same_v<Meth, reg_algo::SearchMethod>
97 || std::is_same_v<Meth, reg_algo::SortMethod>
98consteval std::string_view alias()
99{
100 return TypeInfo<reg_algo::ApplyAlgorithm>::fields.find(REFLECTION_STR(TypeInfo<Meth>::name))
101 .attrs.find(REFLECTION_STR("alias"))
102 .value;
103}
104//! @brief Get the alias attribute directly for sub-cli related registrations.
105//! @tparam Inst - type of sub-cli's category
106//! @return alias attribute
107template <typename Inst>
108requires std::is_same_v<Inst, reg_dp::BehavioralInstance> || std::is_same_v<Inst, reg_dp::CreationalInstance>
109 || std::is_same_v<Inst, reg_dp::StructuralInstance>
110consteval std::string_view alias()
111{
112 return TypeInfo<reg_dp::ApplyDesignPattern>::fields.find(REFLECTION_STR(TypeInfo<Inst>::name))
113 .attrs.find(REFLECTION_STR("alias"))
114 .value;
115}
116//! @brief Get the alias attribute directly for sub-cli related registrations.
117//! @tparam Inst - type of sub-cli's category
118//! @return alias attribute
119template <typename Inst>
120requires std::is_same_v<Inst, reg_ds::CacheInstance> || std::is_same_v<Inst, reg_ds::FilterInstance>
121 || std::is_same_v<Inst, reg_ds::GraphInstance> || std::is_same_v<Inst, reg_ds::HeapInstance>
122 || std::is_same_v<Inst, reg_ds::LinearInstance> || std::is_same_v<Inst, reg_ds::TreeInstance>
123consteval std::string_view alias()
124{
125 return TypeInfo<reg_ds::ApplyDataStructure>::fields.find(REFLECTION_STR(TypeInfo<Inst>::name))
126 .attrs.find(REFLECTION_STR("alias"))
127 .value;
128}
129//! @brief Get the alias attribute directly for sub-cli related registrations.
130//! @tparam Meth - type of sub-cli's category
131//! @return alias attribute
132template <typename Meth>
133requires std::is_same_v<Meth, reg_num::ArithmeticMethod> || std::is_same_v<Meth, reg_num::DivisorMethod>
134 || std::is_same_v<Meth, reg_num::IntegralMethod> || std::is_same_v<Meth, reg_num::PrimeMethod>
135consteval std::string_view alias()
136{
137 return TypeInfo<reg_num::ApplyNumeric>::fields.find(REFLECTION_STR(TypeInfo<Meth>::name))
138 .attrs.find(REFLECTION_STR("alias"))
139 .value;
140}
141//! @brief Get the description attribute directly for sub-cli related registrations.
142//! @tparam MappedCLI - type of sub-cli or sub-cli's category
143//! @return description attribute
144template <typename MappedCLI>
145consteval std::string_view descr()
146{
147 return TypeInfo<MappedCLI>::attrs.find(REFLECTION_STR("descr")).value;
148}
149
150//! @brief The "Set Choice" message in the applied action.
151//! @tparam Evt - type of applied action event
152template <typename Evt>
153struct SetChoice
154{
155 //! @brief Target choice.
156 const std::string choice;
157};
158//! @brief The "Run Candidates" message in the applied action.
159//! @tparam Evt - type of applied action event
160template <typename Evt>
161struct RunCandidates
162{
163 //! @brief Collection of candidates for choice.
164 const std::vector<std::string> candidates;
165};
166//! @brief Indication type of setting in the applied action.
167//! @tparam Msg - type of message
168template <typename Msg>
169struct SettingIndication;
170//! @brief Indication type of running in the applied action.
171//! @tparam Msg - type of message
172template <typename Msg>
173struct RunningIndication;
174//! @brief Message type list.
175//! @tparam Types - type of indication types
176template <typename... Types>
177struct MessageTypeList
178{
179 //! @brief Alias for the parameter pack.
180 //! @tparam InnerTypes - type of inner types
181 //! @tparam TemplatedType - type of templated type
182 template <template <typename... InnerTypes> class TemplatedType>
183 using AsParameterPackFor = TemplatedType<Types...>;
184 //! @brief Alias for the providing interface.
185 //! @tparam Intf - type of interface
186 template <typename Intf>
187 using WithInterface = MessageTypeList<Types..., Intf>;
188};
189//! @brief Alias for the message type list.
190using MessageTypes = MessageTypeList<
191 SettingIndication<SetChoice<reg_algo::MatchMethod>>,
192 RunningIndication<RunCandidates<reg_algo::MatchMethod>>,
193 SettingIndication<SetChoice<reg_algo::NotationMethod>>,
194 RunningIndication<RunCandidates<reg_algo::NotationMethod>>,
195 SettingIndication<SetChoice<reg_algo::OptimalMethod>>,
196 RunningIndication<RunCandidates<reg_algo::OptimalMethod>>,
197 SettingIndication<SetChoice<reg_algo::SearchMethod>>,
198 RunningIndication<RunCandidates<reg_algo::SearchMethod>>,
199 SettingIndication<SetChoice<reg_algo::SortMethod>>,
200 RunningIndication<RunCandidates<reg_algo::SortMethod>>,
201 SettingIndication<SetChoice<reg_dp::BehavioralInstance>>,
202 RunningIndication<RunCandidates<reg_dp::BehavioralInstance>>,
203 SettingIndication<SetChoice<reg_dp::CreationalInstance>>,
204 RunningIndication<RunCandidates<reg_dp::CreationalInstance>>,
205 SettingIndication<SetChoice<reg_dp::StructuralInstance>>,
206 RunningIndication<RunCandidates<reg_dp::StructuralInstance>>,
207 SettingIndication<SetChoice<reg_ds::CacheInstance>>,
208 RunningIndication<RunCandidates<reg_ds::CacheInstance>>,
209 SettingIndication<SetChoice<reg_ds::FilterInstance>>,
210 RunningIndication<RunCandidates<reg_ds::FilterInstance>>,
211 SettingIndication<SetChoice<reg_ds::GraphInstance>>,
212 RunningIndication<RunCandidates<reg_ds::GraphInstance>>,
213 SettingIndication<SetChoice<reg_ds::HeapInstance>>,
214 RunningIndication<RunCandidates<reg_ds::HeapInstance>>,
215 SettingIndication<SetChoice<reg_ds::LinearInstance>>,
216 RunningIndication<RunCandidates<reg_ds::LinearInstance>>,
217 SettingIndication<SetChoice<reg_ds::TreeInstance>>,
218 RunningIndication<RunCandidates<reg_ds::TreeInstance>>,
219 SettingIndication<SetChoice<reg_num::ArithmeticMethod>>,
220 RunningIndication<RunCandidates<reg_num::ArithmeticMethod>>,
221 SettingIndication<SetChoice<reg_num::DivisorMethod>>,
222 RunningIndication<RunCandidates<reg_num::DivisorMethod>>,
223 SettingIndication<SetChoice<reg_num::IntegralMethod>>,
224 RunningIndication<RunCandidates<reg_num::IntegralMethod>>,
225 SettingIndication<SetChoice<reg_num::PrimeMethod>>,
226 RunningIndication<RunCandidates<reg_num::PrimeMethod>>>;
227
228//! @brief Alias for the message handler.
229//! @tparam Msg - type of message
230template <typename Msg>
231using Handler = std::function<void(const Msg&)>;
232//! @brief Message dispatcher.
233//! @tparam Is - type of indications
234template <typename... Is>
235class Dispatcher;
236//! @brief Message dispatcher of the setting indication.
237//! @tparam Msg - type of message
238//! @tparam Is - type of indications
239template <typename Msg, typename... Is>
240class Dispatcher<SettingIndication<Msg>, Is...> : public Dispatcher<Is...>
241{
242public:
243 using Dispatcher<Is...>::registerHandler;
244 //! @brief Register the handler.
245 //! @param handling - handling for message
246 virtual void registerHandler(Handler<Msg> handling) = 0;
247};
248//! @brief Message dispatcher of the running indication.
249//! @tparam Msg - type of messages
250//! @tparam Is - type of indications
251template <typename Msg, typename... Is>
252class Dispatcher<RunningIndication<Msg>, Is...> : public Dispatcher<Is...>
253{
254public:
255 using Dispatcher<Is...>::registerHandler;
256 //! @brief Register the handler.
257 //! @param handling - handling for message
258 virtual void registerHandler(Handler<Msg> handling) = 0;
259};
260//! @brief Default message dispatcher.
261template <>
262class Dispatcher<>
263{
264public:
265 //! @brief Construct a new Dispatcher object.
266 Dispatcher() = default;
267 //! @brief Destroy the Dispatcher object.
268 virtual ~Dispatcher() = default;
269 //! @brief Construct a new Dispatcher object.
270 Dispatcher(const Dispatcher&) = default;
271 //! @brief Construct a new Dispatcher object.
272 Dispatcher(Dispatcher&&) noexcept = default;
273 //! @brief The operator (=) overloading of Dispatcher class.
274 //! @return reference of the Dispatcher object
275 Dispatcher& operator=(const Dispatcher&) = default;
276 //! @brief The operator (=) overloading of Dispatcher class.
277 //! @return reference of the Dispatcher object
278 Dispatcher& operator=(Dispatcher&&) noexcept = default;
279
280 //! @brief Register the handler.
281 void registerHandler();
282};
283//! @brief Message receiver.
284//! @tparam Is - type of indications
285template <typename... Is>
286class Receiver;
287//! @brief Message receiver of the setting indication.
288//! @tparam Msg - type of message
289//! @tparam Is - type of indications
290template <typename Msg, typename... Is>
291class Receiver<SettingIndication<Msg>, Is...> : public Receiver<Is...>
292{
293public:
294 using Receiver<Is...>::onMessage;
295 //! @brief Action on message.
296 //! @param message - message body
297 virtual void onMessage(const Msg& message) = 0;
298};
299//! @brief Message receiver of the running indication.
300//! @tparam Msg - type of message
301//! @tparam Is - type of indications
302template <typename Msg, typename... Is>
303class Receiver<RunningIndication<Msg>, Is...> : public Receiver<Is...>
304{
305public:
306 using Receiver<Is...>::onMessage;
307 //! @brief Action on message.
308 //! @param message - message body
309 virtual void onMessage(const Msg& message) = 0;
310};
311//! @brief Default message receiver.
312template <>
313class Receiver<>
314{
315public:
316 //! @brief Construct a new Receiver object.
317 Receiver() = default;
318 //! @brief Destroy the Receiver object.
319 virtual ~Receiver() = default;
320 //! @brief Construct a new Receiver object.
321 Receiver(const Receiver&) = default;
322 //! @brief Construct a new Receiver object.
323 Receiver(Receiver&&) noexcept = default;
324 //! @brief The operator (=) overloading of Receiver class.
325 //! @return reference of the Receiver object
326 Receiver& operator=(const Receiver&) = default;
327 //! @brief The operator (=) overloading of Receiver class.
328 //! @return reference of the Receiver object
329 Receiver& operator=(Receiver&&) noexcept = default;
330
331 //! @brief Action on message.
332 void onMessage();
333};
334//! @brief Forwarding basis for all message types.
335struct ForwardBase : public MessageTypes::AsParameterPackFor<Dispatcher>,
336 public MessageTypes::AsParameterPackFor<Receiver>
337{
338};
339//! @brief Forwarding action.
340//! @tparam Is - type of indications
341template <typename... Is>
342class Forward;
343//! @brief Forward message of the setting indication.
344//! @tparam Msg - type of message
345//! @tparam Is - type of indications
346template <typename Msg, typename... Is>
347class Forward<SettingIndication<Msg>, Is...> : public Forward<Is...>
348{
349public:
350 //! @brief Alias for the base class.
351 using Base = Forward<Is...>;
352 using Base::registerHandler, Base::onMessage;
353 //! @brief Register the handler.
354 //! @param handling - handling for message
355 void registerHandler(Handler<Msg> handling) override;
356 //! @brief Action on message.
357 //! @param message - message body
358 void onMessage(const Msg& message) override;
359
360private:
361 //! @brief Message handler.
362 Handler<Msg> handler{};
363};
364template <typename Msg, typename... Is>
365void Forward<SettingIndication<Msg>, Is...>::registerHandler(Handler<Msg> handling)
366{
367 handler = std::move(handling);
368}
369template <typename Msg, typename... Is>
370void Forward<SettingIndication<Msg>, Is...>::onMessage(const Msg& message)
371{
372 if (handler)
373 {
374 handler(message);
375 }
376}
377//! @brief Forward message of the running indication.
378//! @tparam Msg - type of message
379//! @tparam Is - type of indications
380template <typename Msg, typename... Is>
381class Forward<RunningIndication<Msg>, Is...> : public Forward<Is...>
382{
383public:
384 //! @brief Alias for the base class.
385 using Base = Forward<Is...>;
386 using Base::registerHandler, Base::onMessage;
387 //! @brief Register the handler.
388 //! @param handling - handling for message
389 void registerHandler(Handler<Msg> handling) override;
390 //! @brief Action on message.
391 //! @param message - message body
392 void onMessage(const Msg& message) override;
393
394private:
395 //! @brief Message handler.
396 Handler<Msg> handler{};
397};
398template <typename Msg, typename... Is>
399void Forward<RunningIndication<Msg>, Is...>::registerHandler(Handler<Msg> handling)
400{
401 handler = std::move(handling);
402}
403template <typename Msg, typename... Is>
404void Forward<RunningIndication<Msg>, Is...>::onMessage(const Msg& message)
405{
406 if (handler)
407 {
408 handler(message);
409 }
410}
411//! @brief Forwarding action interface.
412//! @tparam Intf - type of interface
413template <typename Intf>
414class Forward<Intf> : public Intf
415{
416};
417
418//! @brief Message forwarder.
419struct MessageForwarder : public MessageTypes::WithInterface<ForwardBase>::AsParameterPackFor<Forward>
420{
421};
422
423//! @brief Alias for the applied action event type.
424using EventType = std::variant<
425 reg_algo::MatchMethod,
426 reg_algo::NotationMethod,
427 reg_algo::OptimalMethod,
428 reg_algo::SearchMethod,
429 reg_algo::SortMethod,
430 reg_dp::BehavioralInstance,
431 reg_dp::CreationalInstance,
432 reg_dp::StructuralInstance,
433 reg_ds::CacheInstance,
434 reg_ds::FilterInstance,
435 reg_ds::GraphInstance,
436 reg_ds::HeapInstance,
437 reg_ds::LinearInstance,
438 reg_ds::TreeInstance,
439 reg_num::ArithmeticMethod,
440 reg_num::DivisorMethod,
441 reg_num::IntegralMethod,
442 reg_num::PrimeMethod>;
443} // namespace action
444} // namespace application
445