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-2026 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
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 Constraint for design-pattern-registering.
148//! @tparam Inst - type of instance
149template <typename Inst>
150concept Registrant = std::is_same_v<Inst, BehavioralInstance> || std::is_same_v<Inst, CreationalInstance>
151 || std::is_same_v<Inst, StructuralInstance>;
152//! @brief Set the choice.
153//! @tparam Inst - type of target instance
154//! @param choice - target choice
155template <typename Inst>
156requires Registrant<Inst>
157void setChoice(const std::string& choice);
158//! @brief Run the candidates.
159//! @tparam Inst - type of target instance
160//! @param candidates - container for the candidate target choices
161template <typename Inst>
162requires Registrant<Inst>
163void runCandidates(const std::vector<std::string>& candidates);
164
165//! @brief Register behavioral.
166namespace behavioral
167{
168extern const char* version() noexcept;
169} // namespace behavioral
170template <>
171void setChoice<BehavioralInstance>(const std::string& choice);
172template <>
173void runCandidates<BehavioralInstance>(const std::vector<std::string>& candidates);
174
175//! @brief Register creational.
176namespace creational
177{
178extern const char* version() noexcept;
179} // namespace creational
180template <>
181void setChoice<CreationalInstance>(const std::string& choice);
182template <>
183void runCandidates<CreationalInstance>(const std::vector<std::string>& candidates);
184
185//! @brief Register structural.
186namespace structural
187{
188extern const char* version() noexcept;
189} // namespace structural
190template <>
191void setChoice<StructuralInstance>(const std::string& choice);
192template <>
193void runCandidates<StructuralInstance>(const std::vector<std::string>& candidates);
194} // namespace reg_dp
195} // namespace application
196
197//! @brief Reflect the design pattern category name and alias name to the field in the mapping.
198#define REG_DP_REFLECT_FIRST_LEVEL_FIELD(category, alias) \
199 Field \
200 { \
201 REFLECTION_STR(MACRO_STRINGIFY(category)), &Type::MACRO_CONCAT(category, Opts), AttrList \
202 { \
203 Attr \
204 { \
205 REFLECTION_STR("alias"), MACRO_STRINGIFY(alias) \
206 } \
207 } \
208 }
209//! @brief Reflect the entry under the design pattern category and choice name to the field in the mapping.
210#define REG_DP_REFLECT_SECOND_LEVEL_FIELD(entry, choice) \
211 Field \
212 { \
213 REFLECTION_STR(MACRO_STRINGIFY(entry)), Type::entry, AttrList \
214 { \
215 Attr \
216 { \
217 REFLECTION_STR("choice"), MACRO_STRINGIFY(choice) \
218 } \
219 } \
220 }
221//! @brief Static reflection for ApplyDesignPattern. Used to map command line arguments.
222template <>
223struct utility::reflection::TypeInfo<application::reg_dp::ApplyDesignPattern>
224 : public TypeInfoImpl<application::reg_dp::ApplyDesignPattern>
225{
226 //! @brief Name.
227 static constexpr std::string_view name{"app-dp"};
228 // clang-format off
229 //! @brief Field list.
230 static constexpr FieldList fields
231 {
232 REG_DP_REFLECT_FIRST_LEVEL_FIELD(behavioral, b),
233 REG_DP_REFLECT_FIRST_LEVEL_FIELD(creational, c),
234 REG_DP_REFLECT_FIRST_LEVEL_FIELD(structural, s),
235 };
236 // clang-format on
237 //! @brief Attribute list.
238 static constexpr AttrList attrs{Attr{REFLECTION_STR("descr"), "apply design pattern"}};
239};
240//! @brief Static reflection for BehavioralInstance. Used to map command line arguments.
241template <>
242struct utility::reflection::TypeInfo<application::reg_dp::BehavioralInstance>
243 : public TypeInfoImpl<application::reg_dp::BehavioralInstance>
244{
245 //! @brief Name.
246 static constexpr std::string_view name{"behavioral"};
247 // clang-format off
248 //! @brief Field list.
249 static constexpr FieldList fields
250 {
251 REG_DP_REFLECT_SECOND_LEVEL_FIELD(chainOfResponsibility, cha),
252 REG_DP_REFLECT_SECOND_LEVEL_FIELD(command , com),
253 REG_DP_REFLECT_SECOND_LEVEL_FIELD(interpreter , int),
254 REG_DP_REFLECT_SECOND_LEVEL_FIELD(iterator , ite),
255 REG_DP_REFLECT_SECOND_LEVEL_FIELD(mediator , med),
256 REG_DP_REFLECT_SECOND_LEVEL_FIELD(memento , mem),
257 REG_DP_REFLECT_SECOND_LEVEL_FIELD(observer , obs),
258 REG_DP_REFLECT_SECOND_LEVEL_FIELD(state , sta),
259 REG_DP_REFLECT_SECOND_LEVEL_FIELD(strategy , str),
260 REG_DP_REFLECT_SECOND_LEVEL_FIELD(templateMethod , tem),
261 REG_DP_REFLECT_SECOND_LEVEL_FIELD(visitor , vis),
262 };
263 // clang-format on
264 //! @brief Attribute list.
265 static constexpr AttrList attrs{Attr{
266 REFLECTION_STR("descr"),
267 "behavioral-related choices\n"
268 "- cha Chain Of Responsibility\n"
269 "- com Command\n"
270 "- int Interpreter\n"
271 "- ite Iterator\n"
272 "- med Mediator\n"
273 "- mem Memento\n"
274 "- obs Observer\n"
275 "- sta State\n"
276 "- str Strategy\n"
277 "- tem Template Method\n"
278 "- vis Visitor\n"
279 "add the choices listed above"}};
280};
281//! @brief Static reflection for CreationalInstance. Used to map command line arguments.
282template <>
283struct utility::reflection::TypeInfo<application::reg_dp::CreationalInstance>
284 : public TypeInfoImpl<application::reg_dp::CreationalInstance>
285{
286 //! @brief Name.
287 static constexpr std::string_view name{"creational"};
288 // clang-format off
289 //! @brief Field list.
290 static constexpr FieldList fields
291 {
292 REG_DP_REFLECT_SECOND_LEVEL_FIELD(abstractFactory, abs),
293 REG_DP_REFLECT_SECOND_LEVEL_FIELD(builder , bui),
294 REG_DP_REFLECT_SECOND_LEVEL_FIELD(factoryMethod , fac),
295 REG_DP_REFLECT_SECOND_LEVEL_FIELD(prototype , pro),
296 REG_DP_REFLECT_SECOND_LEVEL_FIELD(singleton , sin),
297 };
298 // clang-format on
299 //! @brief Attribute list.
300 static constexpr AttrList attrs{Attr{
301 REFLECTION_STR("descr"),
302 "creational-related choices\n"
303 "- abs Abstract Factory\n"
304 "- bui Builder\n"
305 "- fac Factory Method\n"
306 "- pro Prototype\n"
307 "- sin Singleton\n"
308 "add the choices listed above"}};
309};
310//! @brief Static reflection for StructuralInstance. Used to map command line arguments.
311template <>
312struct utility::reflection::TypeInfo<application::reg_dp::StructuralInstance>
313 : public TypeInfoImpl<application::reg_dp::StructuralInstance>
314{
315 //! @brief Name.
316 static constexpr std::string_view name{"structural"};
317 // clang-format off
318 //! @brief Field list.
319 static constexpr FieldList fields
320 {
321 REG_DP_REFLECT_SECOND_LEVEL_FIELD(adapter , ada),
322 REG_DP_REFLECT_SECOND_LEVEL_FIELD(bridge , bri),
323 REG_DP_REFLECT_SECOND_LEVEL_FIELD(composite, com),
324 REG_DP_REFLECT_SECOND_LEVEL_FIELD(decorator, dec),
325 REG_DP_REFLECT_SECOND_LEVEL_FIELD(facade , fac),
326 REG_DP_REFLECT_SECOND_LEVEL_FIELD(flyweight, fly),
327 REG_DP_REFLECT_SECOND_LEVEL_FIELD(proxy , pro),
328 };
329 // clang-format on
330 //! @brief Attribute list.
331 static constexpr AttrList attrs{Attr{
332 REFLECTION_STR("descr"),
333 "structural-related choices\n"
334 "- ada Adapter\n"
335 "- bri Bridge\n"
336 "- com Composite\n"
337 "- dec Decorator\n"
338 "- fac Facade\n"
339 "- fly Flyweight\n"
340 "- pro Proxy\n"
341 "add the choices listed above"}};
342};
343#undef REG_DP_REFLECT_FIRST_LEVEL_FIELD
344#undef REG_DP_REFLECT_SECOND_LEVEL_FIELD
345
346namespace application::reg_dp
347{
348//! @brief Alias for the type information.
349//! @tparam UDT - type of user defined data
350template <typename UDT>
351using TypeInfo = utility::reflection::TypeInfo<UDT>;
352//! @brief Alias for the category.
353using Category = ApplyDesignPattern::Category;
354//! @brief Convert category enumeration to string.
355//! @param cat - target category
356//! @return category name
357consteval std::string_view toString(const Category cat)
358{
359 switch (cat)
360 {
361 case Category::behavioral:
362 return TypeInfo<BehavioralInstance>::name;
363 case Category::creational:
364 return TypeInfo<CreationalInstance>::name;
365 case Category::structural:
366 return TypeInfo<StructuralInstance>::name;
367 default:
368 break;
369 }
370 return {};
371}
372//! @brief Get the bit flags of the category in design pattern choices.
373//! @tparam Cat - target category
374//! @return reference of the category bit flags
375template <Category Cat>
376constexpr auto& categoryOpts()
377{
378 return std::invoke(
379 TypeInfo<ApplyDesignPattern>::fields.find(REFLECTION_STR(toString(Cat))).value, manage::choiceApplier());
380}
381//! @brief The literal hash value of the abbreviation for the candidate instance.
382//! @tparam Inst - type of candidate instance
383//! @param instance - candidate instance
384//! @return literal hash value
385template <typename Inst>
386consteval std::size_t abbrLitHash(const Inst instance)
387{
388 static_assert(Bottom<Inst>::value == TypeInfo<Inst>::fields.size);
389 constexpr auto refl = REFLECTION_STR("choice");
390 std::size_t value = 0;
391 TypeInfo<Inst>::fields.findIf(
392 [refl, instance, &value](const auto field)
393 {
394 if (field.name == TypeInfo<Inst>::fields.nameOfValue(instance))
395 {
396 static_assert(field.attrs.contains(refl) && (field.attrs.size == 1));
397 const auto attr = field.attrs.find(refl);
398 static_assert(attr.hasValue);
399 value = utility::common::operator""_bkdrHash(attr.value);
400 return true;
401 }
402 return false;
403 });
404 return value;
405}
406} // namespace application::reg_dp
407