1//! @file schedule.hpp
2//! @author ryftchen
3//! @brief The declarations (schedule) 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#include <map>
12#else
13#include "application/pch/precompiled_header.hpp"
14#endif
15
16#include "application/example/include/register_algorithm.hpp"
17#include "application/example/include/register_data_structure.hpp"
18#include "application/example/include/register_design_pattern.hpp"
19#include "application/example/include/register_numeric.hpp"
20
21//! @brief The application module.
22namespace application // NOLINT(modernize-concat-nested-namespaces)
23{
24//! @brief Applied-schedule-related functions in the application module.
25namespace schedule
26{
27//! @brief Awaitable coroutine.
28class Awaitable final
29{
30public:
31 // NOLINTBEGIN(readability-identifier-naming)
32 //! @brief Promise type for use in coroutines.
33 struct promise_type
34 {
35 //! @brief Get the return object for the coroutine.
36 //! @return awaitable instance
37 Awaitable get_return_object() { return Awaitable{std::coroutine_handle<promise_type>::from_promise(p&: *this)}; }
38 //! @brief Initial suspend point of the coroutine.
39 //! @return std::suspend_never object indicating that the coroutine should not be suspended initially
40 static std::suspend_never initial_suspend() noexcept { return {}; }
41 //! @brief Final suspend point of the coroutine.
42 //! @return std::suspend_always object indicating that the coroutine should be suspended finally
43 static std::suspend_always final_suspend() noexcept { return {}; }
44 //! @brief Complete the coroutine without returning a value.
45 static void return_void() noexcept {}
46 //! @brief Handle exceptions thrown within the coroutine.
47 static void unhandled_exception() { std::rethrow_exception(std::current_exception()); }
48 };
49 // NOLINTEND(readability-identifier-naming)
50
51 //! @brief Construct a new Awaitable object.
52 //! @param handle - coroutine handle
53 explicit Awaitable(const std::coroutine_handle<promise_type>& handle);
54 //! @brief Destroy the Awaitable object.
55 ~Awaitable();
56 //! @brief Construct a new Awaitable object.
57 Awaitable(const Awaitable&) = delete;
58 //! @brief Construct a new Awaitable object.
59 Awaitable(Awaitable&&) = delete;
60 //! @brief The operator (=) overloading of Awaitable class.
61 //! @return reference of the Awaitable object
62 Awaitable& operator=(const Awaitable&) = delete;
63 //! @brief The operator (=) overloading of Awaitable class.
64 //! @return reference of the Awaitable object
65 Awaitable& operator=(Awaitable&&) = delete;
66
67 //! @brief Resume the execution of the coroutine if it is suspended.
68 void resume() const;
69 //! @brief Check whether the coroutine has been completed.
70 //! @return be done or not
71 [[nodiscard]] bool done() const;
72
73private:
74 //! @brief Coroutine handle.
75 std::coroutine_handle<promise_type> handle;
76 //! @brief Flag to ensure only one instance is active.
77 static std::atomic_bool active;
78};
79
80extern void enterNextPhase(Awaitable& awaitable);
81
82//! @brief Native schedule.
83namespace native
84{
85//! @brief Represent the maximum value of an enum.
86//! @tparam Enum - type of specific enum
87template <typename Enum>
88struct Bottom;
89
90//! @brief Enumerate specific native categories.
91enum class Category : std::uint8_t
92{
93 //! @brief Console.
94 console,
95 //! @brief Dump.
96 dump,
97 //! @brief Help.
98 help,
99 //! @brief Version.
100 version
101};
102//! @brief Store the maximum value of the Category enum.
103template <>
104struct Bottom<Category>
105{
106 //! @brief Maximum value of the Category enum.
107 static constexpr std::uint8_t value{4};
108};
109
110//! @brief Gather and notify handlers.
111//! @tparam Ctx - type of context
112//! @tparam Key - type of key
113template <typename Ctx, typename Key = Category>
114class Notifier
115{
116public:
117 //! @brief The base procedure when notified.
118 class Procedure
119 {
120 public:
121 //! @brief Destroy the Procedure object.
122 virtual ~Procedure() = default;
123
124 //! @brief Perform the specific operation.
125 virtual void execute() const = 0;
126 };
127 //! @brief The procedure when notified.
128 //! @tparam CRTP - type of derived class
129 template <typename CRTP>
130 class ProcedureImpl : public Procedure
131 {
132 public:
133 //! @brief Perform the specific operation.
134 void execute() const override { static_cast<const CRTP&>(*this).execute(); }
135 };
136 //! @brief The handler used to trigger a procedure when notified.
137 //! @tparam key - specific key
138 template <Key key>
139 class Handler : public ProcedureImpl<Handler<key>>
140 {
141 public:
142 //! @brief Construct a new Handler object.
143 //! @param ctx - involved context
144 explicit Handler(const Ctx& ctx) : ctx{ctx} {}
145
146 //! @brief Perform the specific operation.
147 void execute() const override;
148
149 private:
150 //! @brief The involved context.
151 const Ctx& ctx{};
152 };
153
154 //! @brief Attach a handler with a specific key to the notifier.
155 //! @param key - specific key
156 //! @param handler - handler to be attached
157 void attach(const Key key, std::shared_ptr<Procedure> handler);
158 //! @brief Notify the handler associated with the given key.
159 //! @param key - specific key
160 void notify(const Key key) const;
161
162private:
163 //! @brief Map of handlers identified by a key.
164 std::map<Key, std::shared_ptr<Procedure>> handlers{};
165};
166
167template <typename Ctx, typename Key>
168void Notifier<Ctx, Key>::attach(const Key key, std::shared_ptr<Procedure> handler)
169{
170 handlers[key] = std::move(handler);
171}
172
173template <typename Ctx, typename Key>
174void Notifier<Ctx, Key>::notify(const Key key) const
175{
176 if (handlers.contains(key))
177 {
178 handlers.at(key)->execute();
179 }
180}
181} // namespace native
182
183//! @brief Extra schedule.
184namespace extra
185{
186//! @brief The "Set Choice" message in the applied action.
187//! @tparam Evt - type of applied action event
188template <typename Evt>
189struct SetChoice
190{
191 //! @brief Target choice.
192 const std::string choice;
193};
194
195//! @brief The "Run Candidates" message in the applied action.
196//! @tparam Evt - type of applied action event
197template <typename Evt>
198struct RunCandidates
199{
200 //! @brief Collection of candidates for choice.
201 const std::vector<std::string> candidates;
202};
203
204//! @brief Indication type of setting in the applied action.
205//! @tparam Msg - type of message
206template <typename Msg>
207struct SettingIndication;
208
209//! @brief Indication type of running in the applied action.
210//! @tparam Msg - type of message
211template <typename Msg>
212struct RunningIndication;
213
214//! @brief Message type list.
215//! @tparam Types - type of indication types
216template <typename... Types>
217struct MessageTypeList
218{
219 //! @brief Alias for the parameter pack.
220 //! @tparam InnerTypes - type of inner types
221 //! @tparam TemplatedType - type of templated type
222 template <template <typename... InnerTypes> class TemplatedType>
223 using AsParameterPackFor = TemplatedType<Types...>;
224 //! @brief Alias for the providing interface.
225 //! @tparam Intf - type of interface
226 template <typename Intf>
227 using WithInterface = MessageTypeList<Types..., Intf>;
228};
229
230//! @brief Alias for the message type list.
231using MessageTypes = MessageTypeList<
232 SettingIndication<SetChoice<reg_algo::MatchMethod>>,
233 RunningIndication<RunCandidates<reg_algo::MatchMethod>>,
234 SettingIndication<SetChoice<reg_algo::NotationMethod>>,
235 RunningIndication<RunCandidates<reg_algo::NotationMethod>>,
236 SettingIndication<SetChoice<reg_algo::OptimalMethod>>,
237 RunningIndication<RunCandidates<reg_algo::OptimalMethod>>,
238 SettingIndication<SetChoice<reg_algo::SearchMethod>>,
239 RunningIndication<RunCandidates<reg_algo::SearchMethod>>,
240 SettingIndication<SetChoice<reg_algo::SortMethod>>,
241 RunningIndication<RunCandidates<reg_algo::SortMethod>>,
242 SettingIndication<SetChoice<reg_dp::BehavioralInstance>>,
243 RunningIndication<RunCandidates<reg_dp::BehavioralInstance>>,
244 SettingIndication<SetChoice<reg_dp::CreationalInstance>>,
245 RunningIndication<RunCandidates<reg_dp::CreationalInstance>>,
246 SettingIndication<SetChoice<reg_dp::StructuralInstance>>,
247 RunningIndication<RunCandidates<reg_dp::StructuralInstance>>,
248 SettingIndication<SetChoice<reg_ds::CacheInstance>>,
249 RunningIndication<RunCandidates<reg_ds::CacheInstance>>,
250 SettingIndication<SetChoice<reg_ds::FilterInstance>>,
251 RunningIndication<RunCandidates<reg_ds::FilterInstance>>,
252 SettingIndication<SetChoice<reg_ds::GraphInstance>>,
253 RunningIndication<RunCandidates<reg_ds::GraphInstance>>,
254 SettingIndication<SetChoice<reg_ds::HeapInstance>>,
255 RunningIndication<RunCandidates<reg_ds::HeapInstance>>,
256 SettingIndication<SetChoice<reg_ds::LinearInstance>>,
257 RunningIndication<RunCandidates<reg_ds::LinearInstance>>,
258 SettingIndication<SetChoice<reg_ds::TreeInstance>>,
259 RunningIndication<RunCandidates<reg_ds::TreeInstance>>,
260 SettingIndication<SetChoice<reg_num::ArithmeticMethod>>,
261 RunningIndication<RunCandidates<reg_num::ArithmeticMethod>>,
262 SettingIndication<SetChoice<reg_num::DivisorMethod>>,
263 RunningIndication<RunCandidates<reg_num::DivisorMethod>>,
264 SettingIndication<SetChoice<reg_num::IntegralMethod>>,
265 RunningIndication<RunCandidates<reg_num::IntegralMethod>>,
266 SettingIndication<SetChoice<reg_num::PrimeMethod>>,
267 RunningIndication<RunCandidates<reg_num::PrimeMethod>>>;
268
269//! @brief Alias for the message handler.
270//! @tparam Msg - type of message
271template <typename Msg>
272using Handler = std::function<void(const Msg&)>;
273
274//! @brief Message dispatcher.
275//! @tparam Is - type of indications
276template <typename... Is>
277class Dispatcher;
278
279//! @brief Message dispatcher of the setting indication.
280//! @tparam Msg - type of message
281//! @tparam Is - type of indications
282template <typename Msg, typename... Is>
283class Dispatcher<SettingIndication<Msg>, Is...> : public Dispatcher<Is...>
284{
285public:
286 using Dispatcher<Is...>::registerHandler;
287 //! @brief Register the handler.
288 //! @param handling - handling for message
289 virtual void registerHandler(Handler<Msg> handling) = 0;
290};
291
292//! @brief Message dispatcher of the running indication.
293//! @tparam Msg - type of messages
294//! @tparam Is - type of indications
295template <typename Msg, typename... Is>
296class Dispatcher<RunningIndication<Msg>, Is...> : public Dispatcher<Is...>
297{
298public:
299 using Dispatcher<Is...>::registerHandler;
300 //! @brief Register the handler.
301 //! @param handling - handling for message
302 virtual void registerHandler(Handler<Msg> handling) = 0;
303};
304
305//! @brief Default message dispatcher.
306template <>
307class Dispatcher<>
308{
309public:
310 //! @brief Destroy the Dispatcher object.
311 virtual ~Dispatcher() = default;
312
313 //! @brief Register the handler.
314 void registerHandler();
315};
316
317//! @brief Message receiver.
318//! @tparam Is - type of indications
319template <typename... Is>
320class Receiver;
321
322//! @brief Message receiver of the setting indication.
323//! @tparam Msg - type of message
324//! @tparam Is - type of indications
325template <typename Msg, typename... Is>
326class Receiver<SettingIndication<Msg>, Is...> : public Receiver<Is...>
327{
328public:
329 using Receiver<Is...>::onMessage;
330 //! @brief Action on message.
331 //! @param message - message body
332 virtual void onMessage(const Msg& message) = 0;
333};
334
335//! @brief Message receiver of the running indication.
336//! @tparam Msg - type of message
337//! @tparam Is - type of indications
338template <typename Msg, typename... Is>
339class Receiver<RunningIndication<Msg>, Is...> : public Receiver<Is...>
340{
341public:
342 using Receiver<Is...>::onMessage;
343 //! @brief Action on message.
344 //! @param message - message body
345 virtual void onMessage(const Msg& message) = 0;
346};
347
348//! @brief Default message receiver.
349template <>
350class Receiver<>
351{
352public:
353 //! @brief Destroy the Receiver object.
354 virtual ~Receiver() = default;
355
356 //! @brief Action on message.
357 void onMessage();
358};
359
360//! @brief Forwarding basis for all message types.
361struct ForwardBase : public MessageTypes::AsParameterPackFor<Dispatcher>,
362 public MessageTypes::AsParameterPackFor<Receiver>
363{
364};
365
366//! @brief Forwarding action.
367//! @tparam Is - type of indications
368template <typename... Is>
369class Forward;
370
371//! @brief Forward message of the setting indication.
372//! @tparam Msg - type of message
373//! @tparam Is - type of indications
374template <typename Msg, typename... Is>
375class Forward<SettingIndication<Msg>, Is...> : public Forward<Is...>
376{
377public:
378 //! @brief Alias for the base class.
379 using Base = Forward<Is...>;
380 using Base::registerHandler, Base::onMessage;
381 //! @brief Register the handler.
382 //! @param handling - handling for message
383 void registerHandler(Handler<Msg> handling) override;
384 //! @brief Action on message.
385 //! @param message - message body
386 void onMessage(const Msg& message) override;
387
388private:
389 //! @brief Message handler.
390 Handler<Msg> handler{};
391};
392
393template <typename Msg, typename... Is>
394void Forward<SettingIndication<Msg>, Is...>::registerHandler(Handler<Msg> handling)
395{
396 handler = std::move(handling);
397}
398
399template <typename Msg, typename... Is>
400void Forward<SettingIndication<Msg>, Is...>::onMessage(const Msg& message)
401{
402 if (handler)
403 {
404 handler(message);
405 }
406}
407
408//! @brief Forward message of the running indication.
409//! @tparam Msg - type of message
410//! @tparam Is - type of indications
411template <typename Msg, typename... Is>
412class Forward<RunningIndication<Msg>, Is...> : public Forward<Is...>
413{
414public:
415 //! @brief Alias for the base class.
416 using Base = Forward<Is...>;
417 using Base::registerHandler, Base::onMessage;
418 //! @brief Register the handler.
419 //! @param handling - handling for message
420 void registerHandler(Handler<Msg> handling) override;
421 //! @brief Action on message.
422 //! @param message - message body
423 void onMessage(const Msg& message) override;
424
425private:
426 //! @brief Message handler.
427 Handler<Msg> handler{};
428};
429
430template <typename Msg, typename... Is>
431void Forward<RunningIndication<Msg>, Is...>::registerHandler(Handler<Msg> handling)
432{
433 handler = std::move(handling);
434}
435
436template <typename Msg, typename... Is>
437void Forward<RunningIndication<Msg>, Is...>::onMessage(const Msg& message)
438{
439 if (handler)
440 {
441 handler(message);
442 }
443}
444
445//! @brief Forwarding action interface.
446//! @tparam Intf - type of interface
447template <typename Intf>
448class Forward<Intf> : public Intf
449{
450};
451
452//! @brief Message forwarder.
453struct MessageForwarder : public MessageTypes::WithInterface<ForwardBase>::AsParameterPackFor<Forward>
454{
455};
456
457//! @brief Alias for the applied action event type.
458using EventType = std::variant<
459 reg_algo::MatchMethod,
460 reg_algo::NotationMethod,
461 reg_algo::OptimalMethod,
462 reg_algo::SearchMethod,
463 reg_algo::SortMethod,
464 reg_dp::BehavioralInstance,
465 reg_dp::CreationalInstance,
466 reg_dp::StructuralInstance,
467 reg_ds::CacheInstance,
468 reg_ds::FilterInstance,
469 reg_ds::GraphInstance,
470 reg_ds::HeapInstance,
471 reg_ds::LinearInstance,
472 reg_ds::TreeInstance,
473 reg_num::ArithmeticMethod,
474 reg_num::DivisorMethod,
475 reg_num::IntegralMethod,
476 reg_num::PrimeMethod>;
477} // namespace extra
478
479//! @brief Manage tasks.
480class TaskManager
481{
482public:
483 //! @brief Destroy the TaskManager object.
484 virtual ~TaskManager() = default;
485
486 //! @brief Check whether any tasks do not exist.
487 //! @return any tasks do not exist or exist
488 [[nodiscard]] virtual bool empty() const = 0;
489 //! @brief Reset bit flags that manage all tasks.
490 virtual void reset() = 0;
491};
492
493//! @brief Manage native categories.
494class NativeManager : virtual public TaskManager
495{
496public:
497 //! @brief Bit flags for managing native categories.
498 std::bitset<native::Bottom<native::Category>::value> nativeCategories;
499
500 //! @brief Check whether any native categories do not exist.
501 //! @return any native categories do not exist or exist
502 [[nodiscard]] bool empty() const override;
503 //! @brief Reset bit flags that manage native categories.
504 void reset() override;
505};
506
507//! @brief Manage extra choices of sub-cli.
508class ExtraManager : virtual public TaskManager
509{
510public:
511 //! @brief Alias for the attribute of the registered sub-cli's category.
512 struct Attr
513 {
514 //! @brief The candidates for the choice.
515 const std::vector<std::string> choices;
516 //! @brief The internal event for applying.
517 const extra::EventType event;
518 };
519 //! @brief Alias for the map of sub-cli's category name and Attr.
520 using CategoryMap = std::map<std::string, Attr>;
521 //! @brief Mapping table of all extra choices. Fill as needed.
522 std::map<std::string, CategoryMap> extraChoiceRegistry;
523
524 //! @brief Wrap interfaces to check for existing and reset extra choices.
525 struct Intf
526 {
527 //! @brief Construct a new Intf object.
528 //! @param presentCb - callback of checking
529 //! @param clearCb - callback of resetting
530 Intf(std::function<bool()> presentCb, std::function<void()> clearCb) :
531 present{std::move(presentCb)}, clear{std::move(clearCb)}
532 {
533 if (!present || !clear)
534 {
535 throw std::runtime_error{"Invalid sub-command interfaces are being used."};
536 }
537 }
538
539 //! @brief Check the existence status of the extra choice.
540 const std::function<bool()> present;
541 //! @brief Reset control of the extra choice.
542 const std::function<void()> clear;
543 };
544 //! @brief Existence status and reset control of the sub-cli to which the extra choices belong.
545 std::map<std::string, Intf> extraChecklist;
546 //! @brief Flag for help only.
547 bool extraHelping{false};
548
549 //! @brief Check whether any extra choices do not exist.
550 //! @return any extra choices do not exist or exist
551 [[nodiscard]] bool empty() const override;
552 //! @brief Reset bit flags that manage extra choices.
553 void reset() override;
554};
555
556//! @brief Schedule all managed tasks.
557class TaskScheduler : public NativeManager, public ExtraManager
558{
559public:
560 //! @brief Check whether any tasks do not exist.
561 //! @return any tasks do not exist or exist
562 [[nodiscard]] bool empty() const final;
563 //! @brief Reset bit flags that manage all tasks.
564 void reset() final;
565};
566
567//! @brief Registration metadata.
568namespace meta
569{
570//! @brief Alias for the type information.
571//! @tparam UDT - type of user defined data
572template <typename UDT>
573using TypeInfo = utility::reflection::TypeInfo<UDT>;
574
575//! @brief Get the name field directly for sub-cli related registrations.
576//! @tparam Mapped - type of sub-cli or sub-cli's category
577//! @return name field
578template <typename Mapped>
579consteval std::string_view name()
580{
581 return TypeInfo<Mapped>::name;
582}
583
584//! @brief Get the alias attribute directly for sub-cli related registrations.
585//! @tparam Meth - type of sub-cli's category
586//! @return alias attribute
587template <typename Meth>
588requires reg_algo::Registrant<Meth>
589consteval std::string_view alias()
590{
591 return TypeInfo<reg_algo::ApplyAlgorithm>::fields.find(REFLECTION_STR(TypeInfo<Meth>::name))
592 .attrs.find(REFLECTION_STR("alias"))
593 .value;
594}
595
596//! @brief Get the alias attribute directly for sub-cli related registrations.
597//! @tparam Inst - type of sub-cli's category
598//! @return alias attribute
599template <typename Inst>
600requires reg_dp::Registrant<Inst>
601consteval std::string_view alias()
602{
603 return TypeInfo<reg_dp::ApplyDesignPattern>::fields.find(REFLECTION_STR(TypeInfo<Inst>::name))
604 .attrs.find(REFLECTION_STR("alias"))
605 .value;
606}
607
608//! @brief Get the alias attribute directly for sub-cli related registrations.
609//! @tparam Inst - type of sub-cli's category
610//! @return alias attribute
611template <typename Inst>
612requires reg_ds::Registrant<Inst>
613consteval std::string_view alias()
614{
615 return TypeInfo<reg_ds::ApplyDataStructure>::fields.find(REFLECTION_STR(TypeInfo<Inst>::name))
616 .attrs.find(REFLECTION_STR("alias"))
617 .value;
618}
619
620//! @brief Get the alias attribute directly for sub-cli related registrations.
621//! @tparam Meth - type of sub-cli's category
622//! @return alias attribute
623template <typename Meth>
624requires reg_num::Registrant<Meth>
625consteval std::string_view alias()
626{
627 return TypeInfo<reg_num::ApplyNumeric>::fields.find(REFLECTION_STR(TypeInfo<Meth>::name))
628 .attrs.find(REFLECTION_STR("alias"))
629 .value;
630}
631
632//! @brief Get the description attribute directly for sub-cli related registrations.
633//! @tparam Mapped - type of sub-cli or sub-cli's category
634//! @return description attribute
635template <typename Mapped>
636consteval std::string_view descr()
637{
638 return TypeInfo<Mapped>::attrs.find(REFLECTION_STR("descr")).value;
639}
640
641//! @brief Extract all choices in the sub-cli's category.
642//! @tparam Cat - type of sub-cli's category
643//! @return all choices
644template <typename Cat>
645constexpr auto choice()
646{
647 constexpr auto refl = REFLECTION_STR("choice");
648 std::vector<std::string> choices{};
649 choices.reserve(n: TypeInfo<Cat>::fields.size);
650 TypeInfo<Cat>::fields.forEach(
651 [refl, &choices](const auto field)
652 {
653 static_assert(field.attrs.contains(refl) && (field.attrs.size == 1));
654 const auto attr = field.attrs.find(refl);
655 static_assert(attr.hasValue);
656 choices.emplace_back(attr.value);
657 });
658 return choices;
659}
660} // namespace meta
661} // namespace schedule
662} // namespace application
663