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-2026 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
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 Destroy the Dispatcher object.
266 virtual ~Dispatcher() = default;
267
268 //! @brief Register the handler.
269 void registerHandler();
270};
271//! @brief Message receiver.
272//! @tparam Is - type of indications
273template <typename... Is>
274class Receiver;
275//! @brief Message receiver of the setting indication.
276//! @tparam Msg - type of message
277//! @tparam Is - type of indications
278template <typename Msg, typename... Is>
279class Receiver<SettingIndication<Msg>, Is...> : public Receiver<Is...>
280{
281public:
282 using Receiver<Is...>::onMessage;
283 //! @brief Action on message.
284 //! @param message - message body
285 virtual void onMessage(const Msg& message) = 0;
286};
287//! @brief Message receiver of the running indication.
288//! @tparam Msg - type of message
289//! @tparam Is - type of indications
290template <typename Msg, typename... Is>
291class Receiver<RunningIndication<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 Default message receiver.
300template <>
301class Receiver<>
302{
303public:
304 //! @brief Destroy the Receiver object.
305 virtual ~Receiver() = default;
306
307 //! @brief Action on message.
308 void onMessage();
309};
310//! @brief Forwarding basis for all message types.
311struct ForwardBase : public MessageTypes::AsParameterPackFor<Dispatcher>,
312 public MessageTypes::AsParameterPackFor<Receiver>
313{
314};
315//! @brief Forwarding action.
316//! @tparam Is - type of indications
317template <typename... Is>
318class Forward;
319//! @brief Forward message of the setting indication.
320//! @tparam Msg - type of message
321//! @tparam Is - type of indications
322template <typename Msg, typename... Is>
323class Forward<SettingIndication<Msg>, Is...> : public Forward<Is...>
324{
325public:
326 //! @brief Alias for the base class.
327 using Base = Forward<Is...>;
328 using Base::registerHandler, Base::onMessage;
329 //! @brief Register the handler.
330 //! @param handling - handling for message
331 void registerHandler(Handler<Msg> handling) override;
332 //! @brief Action on message.
333 //! @param message - message body
334 void onMessage(const Msg& message) override;
335
336private:
337 //! @brief Message handler.
338 Handler<Msg> handler{};
339};
340template <typename Msg, typename... Is>
341void Forward<SettingIndication<Msg>, Is...>::registerHandler(Handler<Msg> handling)
342{
343 handler = std::move(handling);
344}
345template <typename Msg, typename... Is>
346void Forward<SettingIndication<Msg>, Is...>::onMessage(const Msg& message)
347{
348 if (handler)
349 {
350 handler(message);
351 }
352}
353//! @brief Forward message of the running indication.
354//! @tparam Msg - type of message
355//! @tparam Is - type of indications
356template <typename Msg, typename... Is>
357class Forward<RunningIndication<Msg>, Is...> : public Forward<Is...>
358{
359public:
360 //! @brief Alias for the base class.
361 using Base = Forward<Is...>;
362 using Base::registerHandler, Base::onMessage;
363 //! @brief Register the handler.
364 //! @param handling - handling for message
365 void registerHandler(Handler<Msg> handling) override;
366 //! @brief Action on message.
367 //! @param message - message body
368 void onMessage(const Msg& message) override;
369
370private:
371 //! @brief Message handler.
372 Handler<Msg> handler{};
373};
374template <typename Msg, typename... Is>
375void Forward<RunningIndication<Msg>, Is...>::registerHandler(Handler<Msg> handling)
376{
377 handler = std::move(handling);
378}
379template <typename Msg, typename... Is>
380void Forward<RunningIndication<Msg>, Is...>::onMessage(const Msg& message)
381{
382 if (handler)
383 {
384 handler(message);
385 }
386}
387//! @brief Forwarding action interface.
388//! @tparam Intf - type of interface
389template <typename Intf>
390class Forward<Intf> : public Intf
391{
392};
393
394//! @brief Message forwarder.
395struct MessageForwarder : public MessageTypes::WithInterface<ForwardBase>::AsParameterPackFor<Forward>
396{
397};
398
399//! @brief Alias for the applied action event type.
400using EventType = std::variant<
401 reg_algo::MatchMethod,
402 reg_algo::NotationMethod,
403 reg_algo::OptimalMethod,
404 reg_algo::SearchMethod,
405 reg_algo::SortMethod,
406 reg_dp::BehavioralInstance,
407 reg_dp::CreationalInstance,
408 reg_dp::StructuralInstance,
409 reg_ds::CacheInstance,
410 reg_ds::FilterInstance,
411 reg_ds::GraphInstance,
412 reg_ds::HeapInstance,
413 reg_ds::LinearInstance,
414 reg_ds::TreeInstance,
415 reg_num::ArithmeticMethod,
416 reg_num::DivisorMethod,
417 reg_num::IntegralMethod,
418 reg_num::PrimeMethod>;
419} // namespace action
420} // namespace application
421