1//! @file register_design_pattern.hpp
2//! @author ryftchen
3//! @brief The declarations (register_design_pattern) 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 <bitset>
11#include <functional>
12#else
13#include "application/pch/precompiled_header.hpp"
14#endif // _PRECOMPILED_HEADER
15
16#include "utility/include/common.hpp"
17#include "utility/include/macro.hpp"
18#include "utility/include/reflection.hpp"
19
20//! @brief The application module.
21namespace application // NOLINT(modernize-concat-nested-namespaces)
22{
23//! @brief Design-pattern-registering-related functions in the application module.
24namespace reg_dp
25{
26extern const char* version() noexcept;
27
28//! @brief Represent the maximum value of an enum.
29//! @tparam Enum - type of specific enum
30template <typename Enum>
31struct Bottom;
32
33//! @brief Enumerate specific behavioral instances.
34enum class BehavioralInstance : std::uint8_t
35{
36 //! @brief Chain of responsibility.
37 chainOfResponsibility,
38 //! @brief Command.
39 command,
40 //! @brief Interpreter.
41 interpreter,
42 //! @brief Iterator.
43 iterator,
44 //! @brief Mediator.
45 mediator,
46 //! @brief Memento.
47 memento,
48 //! @brief Observer.
49 observer,
50 //! @brief State.
51 state,
52 //! @brief Strategy.
53 strategy,
54 //! @brief Template method.
55 templateMethod,
56 //! @brief Visitor.
57 visitor
58};
59//! @brief Store the maximum value of the BehavioralInstance enum.
60template <>
61struct Bottom<BehavioralInstance>
62{
63 //! @brief Maximum value of the BehavioralInstance enum.
64 static constexpr std::uint8_t value{11};
65};
66
67//! @brief Enumerate specific creational instances.
68enum class CreationalInstance : std::uint8_t
69{
70 //! @brief Abstract factory.
71 abstractFactory,
72 //! @brief Builder.
73 builder,
74 //! @brief Factory method.
75 factoryMethod,
76 //! @brief Prototype.
77 prototype,
78 //! @brief Singleton.
79 singleton
80};
81//! @brief Store the maximum value of the CreationalInstance enum.
82template <>
83struct Bottom<CreationalInstance>
84{
85 //! @brief Maximum value of the CreationalInstance enum.
86 static constexpr std::uint8_t value{5};
87};
88
89//! @brief Enumerate specific structural instances.
90enum class StructuralInstance : std::uint8_t
91{
92 //! @brief Adapter.
93 adapter,
94 //! @brief Bridge.
95 bridge,
96 //! @brief Composite.
97 composite,
98 //! @brief Decorator.
99 decorator,
100 //! @brief Facade.
101 facade,
102 //! @brief Flyweight.
103 flyweight,
104 //! @brief Proxy.
105 proxy
106};
107//! @brief Store the maximum value of the StructuralInstance enum.
108template <>
109struct Bottom<StructuralInstance>
110{
111 //! @brief Maximum value of the StructuralInstance enum.
112 static constexpr std::uint8_t value{7};
113};
114
115//! @brief Manage design pattern choices.
116class ApplyDesignPattern
117{
118public:
119 //! @brief Enumerate specific design pattern choices.
120 enum class Category : std::uint8_t
121 {
122 //! @brief Behavioral.
123 behavioral,
124 //! @brief Creational.
125 creational,
126 //! @brief Structural.
127 structural
128 };
129
130 //! @brief Bit flags for managing behavioral instances.
131 std::bitset<Bottom<BehavioralInstance>::value> behavioralOpts;
132 //! @brief Bit flags for managing creational instances.
133 std::bitset<Bottom<CreationalInstance>::value> creationalOpts;
134 //! @brief Bit flags for managing structural instances.
135 std::bitset<Bottom<StructuralInstance>::value> structuralOpts;
136};
137
138//! @brief Manage the design pattern choices.
139namespace manage
140{
141extern ApplyDesignPattern& choiceApplier();
142
143extern bool present();
144extern void clear();
145} // namespace manage
146
147//! @brief Set choice.
148//! @tparam Inst - type of target instance
149//! @param choice - target choice
150template <typename Inst>
151void setChoice(const std::string& choice);
152//! @brief Run candidates.
153//! @tparam Inst - type of target instance
154//! @param candidates - container for the candidate target choices
155template <typename Inst>
156void runCandidates(const std::vector<std::string>& candidates);
157
158//! @brief Register behavioral.
159namespace behavioral
160{
161extern const char* version() noexcept;
162} // namespace behavioral
163template <>
164void setChoice<BehavioralInstance>(const std::string& choice);
165template <>
166void runCandidates<BehavioralInstance>(const std::vector<std::string>& candidates);
167
168//! @brief Register creational.
169namespace creational
170{
171extern const char* version() noexcept;
172} // namespace creational
173template <>
174void setChoice<CreationalInstance>(const std::string& choice);
175template <>
176void runCandidates<CreationalInstance>(const std::vector<std::string>& candidates);
177
178//! @brief Register structural.
179namespace structural
180{
181extern const char* version() noexcept;
182} // namespace structural
183template <>
184void setChoice<StructuralInstance>(const std::string& choice);
185template <>
186void runCandidates<StructuralInstance>(const std::vector<std::string>& candidates);
187} // namespace reg_dp
188} // namespace application
189
190//! @brief Reflect the design pattern category name and alias name to the field in the mapping.
191#define REG_DP_REFLECT_FIRST_LEVEL_FIELD(category, alias) \
192 Field \
193 { \
194 REFLECTION_STR(MACRO_STRINGIFY(category)), &Type::MACRO_CONCAT(category, Opts), AttrList \
195 { \
196 Attr \
197 { \
198 REFLECTION_STR("alias"), MACRO_STRINGIFY(alias) \
199 } \
200 } \
201 }
202//! @brief Reflect the entry under the design pattern category and choice name to the field in the mapping.
203#define REG_DP_REFLECT_SECOND_LEVEL_FIELD(entry, choice) \
204 Field \
205 { \
206 REFLECTION_STR(MACRO_STRINGIFY(entry)), Type::entry, AttrList \
207 { \
208 Attr \
209 { \
210 REFLECTION_STR("choice"), MACRO_STRINGIFY(choice) \
211 } \
212 } \
213 }
214//! @brief Static reflection for ApplyDesignPattern. Used to map command line arguments.
215template <>
216struct utility::reflection::TypeInfo<application::reg_dp::ApplyDesignPattern>
217 : public TypeInfoImpl<application::reg_dp::ApplyDesignPattern>
218{
219 //! @brief Name.
220 static constexpr std::string_view name{"app-dp"};
221 // clang-format off
222 //! @brief Field list.
223 static constexpr FieldList fields
224 {
225 REG_DP_REFLECT_FIRST_LEVEL_FIELD(behavioral, b),
226 REG_DP_REFLECT_FIRST_LEVEL_FIELD(creational, c),
227 REG_DP_REFLECT_FIRST_LEVEL_FIELD(structural, s),
228 };
229 // clang-format on
230 //! @brief Attribute list.
231 static constexpr AttrList attrs{Attr{REFLECTION_STR("descr"), "apply design pattern"}};
232};
233//! @brief Static reflection for BehavioralInstance. Used to map command line arguments.
234template <>
235struct utility::reflection::TypeInfo<application::reg_dp::BehavioralInstance>
236 : public TypeInfoImpl<application::reg_dp::BehavioralInstance>
237{
238 //! @brief Name.
239 static constexpr std::string_view name{"behavioral"};
240 // clang-format off
241 //! @brief Field list.
242 static constexpr FieldList fields
243 {
244 REG_DP_REFLECT_SECOND_LEVEL_FIELD(chainOfResponsibility, cha),
245 REG_DP_REFLECT_SECOND_LEVEL_FIELD(command , com),
246 REG_DP_REFLECT_SECOND_LEVEL_FIELD(interpreter , int),
247 REG_DP_REFLECT_SECOND_LEVEL_FIELD(iterator , ite),
248 REG_DP_REFLECT_SECOND_LEVEL_FIELD(mediator , med),
249 REG_DP_REFLECT_SECOND_LEVEL_FIELD(memento , mem),
250 REG_DP_REFLECT_SECOND_LEVEL_FIELD(observer , obs),
251 REG_DP_REFLECT_SECOND_LEVEL_FIELD(state , sta),
252 REG_DP_REFLECT_SECOND_LEVEL_FIELD(strategy , str),
253 REG_DP_REFLECT_SECOND_LEVEL_FIELD(templateMethod , tem),
254 REG_DP_REFLECT_SECOND_LEVEL_FIELD(visitor , vis),
255 };
256 // clang-format on
257 //! @brief Attribute list.
258 static constexpr AttrList attrs{Attr{
259 REFLECTION_STR("descr"),
260 "behavioral-related choices\n"
261 "- cha Chain Of Responsibility\n"
262 "- com Command\n"
263 "- int Interpreter\n"
264 "- ite Iterator\n"
265 "- med Mediator\n"
266 "- mem Memento\n"
267 "- obs Observer\n"
268 "- sta State\n"
269 "- str Strategy\n"
270 "- tem Template Method\n"
271 "- vis Visitor\n"
272 "add the choices listed above"}};
273};
274//! @brief Static reflection for CreationalInstance. Used to map command line arguments.
275template <>
276struct utility::reflection::TypeInfo<application::reg_dp::CreationalInstance>
277 : public TypeInfoImpl<application::reg_dp::CreationalInstance>
278{
279 //! @brief Name.
280 static constexpr std::string_view name{"creational"};
281 // clang-format off
282 //! @brief Field list.
283 static constexpr FieldList fields
284 {
285 REG_DP_REFLECT_SECOND_LEVEL_FIELD(abstractFactory, abs),
286 REG_DP_REFLECT_SECOND_LEVEL_FIELD(builder , bui),
287 REG_DP_REFLECT_SECOND_LEVEL_FIELD(factoryMethod , fac),
288 REG_DP_REFLECT_SECOND_LEVEL_FIELD(prototype , pro),
289 REG_DP_REFLECT_SECOND_LEVEL_FIELD(singleton , sin),
290 };
291 // clang-format on
292 //! @brief Attribute list.
293 static constexpr AttrList attrs{Attr{
294 REFLECTION_STR("descr"),
295 "creational-related choices\n"
296 "- abs Abstract Factory\n"
297 "- bui Builder\n"
298 "- fac Factory Method\n"
299 "- pro Prototype\n"
300 "- sin Singleton\n"
301 "add the choices listed above"}};
302};
303//! @brief Static reflection for StructuralInstance. Used to map command line arguments.
304template <>
305struct utility::reflection::TypeInfo<application::reg_dp::StructuralInstance>
306 : public TypeInfoImpl<application::reg_dp::StructuralInstance>
307{
308 //! @brief Name.
309 static constexpr std::string_view name{"structural"};
310 // clang-format off
311 //! @brief Field list.
312 static constexpr FieldList fields
313 {
314 REG_DP_REFLECT_SECOND_LEVEL_FIELD(adapter , ada),
315 REG_DP_REFLECT_SECOND_LEVEL_FIELD(bridge , bri),
316 REG_DP_REFLECT_SECOND_LEVEL_FIELD(composite, com),
317 REG_DP_REFLECT_SECOND_LEVEL_FIELD(decorator, dec),
318 REG_DP_REFLECT_SECOND_LEVEL_FIELD(facade , fac),
319 REG_DP_REFLECT_SECOND_LEVEL_FIELD(flyweight, fly),
320 REG_DP_REFLECT_SECOND_LEVEL_FIELD(proxy , pro),
321 };
322 // clang-format on
323 //! @brief Attribute list.
324 static constexpr AttrList attrs{Attr{
325 REFLECTION_STR("descr"),
326 "structural-related choices\n"
327 "- ada Adapter\n"
328 "- bri Bridge\n"
329 "- com Composite\n"
330 "- dec Decorator\n"
331 "- fac Facade\n"
332 "- fly Flyweight\n"
333 "- pro Proxy\n"
334 "add the choices listed above"}};
335};
336#undef REG_DP_REFLECT_FIRST_LEVEL_FIELD
337#undef REG_DP_REFLECT_SECOND_LEVEL_FIELD
338
339namespace application::reg_dp
340{
341//! @brief Alias for the type information.
342//! @tparam UDT - type of user defined data
343template <typename UDT>
344using TypeInfo = utility::reflection::TypeInfo<UDT>;
345//! @brief Alias for the category.
346using Category = ApplyDesignPattern::Category;
347//! @brief Convert category enumeration to string.
348//! @param cat - target category
349//! @return category name
350consteval std::string_view toString(const Category cat)
351{
352 switch (cat)
353 {
354 case Category::behavioral:
355 return TypeInfo<BehavioralInstance>::name;
356 case Category::creational:
357 return TypeInfo<CreationalInstance>::name;
358 case Category::structural:
359 return TypeInfo<StructuralInstance>::name;
360 default:
361 break;
362 }
363 return {};
364}
365//! @brief Get the bit flags of the category in design pattern choices.
366//! @tparam Cat - target category
367//! @return reference of the category bit flags
368template <Category Cat>
369constexpr auto& categoryOpts()
370{
371 return std::invoke(
372 TypeInfo<ApplyDesignPattern>::fields.find(REFLECTION_STR(toString(Cat))).value, manage::choiceApplier());
373}
374//! @brief The literal hash value of the abbreviation for the candidate instance.
375//! @tparam Inst - type of candidate instance
376//! @param instance - candidate instance
377//! @return literal hash value
378template <typename Inst>
379consteval std::size_t abbrLitHash(const Inst instance)
380{
381 static_assert(Bottom<Inst>::value == TypeInfo<Inst>::fields.size);
382 constexpr auto refl = REFLECTION_STR("choice");
383 std::size_t value = 0;
384 TypeInfo<Inst>::fields.findIf(
385 [refl, instance, &value](const auto field)
386 {
387 if (field.name == TypeInfo<Inst>::fields.nameOfValue(instance))
388 {
389 static_assert(field.attrs.contains(refl) && (field.attrs.size == 1));
390 const auto attr = field.attrs.find(refl);
391 static_assert(attr.hasValue);
392 value = utility::common::operator""_bkdrHash(attr.value);
393 return true;
394 }
395 return false;
396 });
397 return value;
398}
399} // namespace application::reg_dp
400