1//! @file register_numeric.hpp
2//! @author ryftchen
3//! @brief The declarations (register_numeric) 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 Numeric-registering-related functions in the application module.
24namespace reg_num
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 arithmetic methods.
34enum class ArithmeticMethod : std::uint8_t
35{
36 //! @brief Addition.
37 addition,
38 //! @brief Subtraction.
39 subtraction,
40 //! @brief Multiplication.
41 multiplication,
42 //! @brief Division.
43 division
44};
45//! @brief Store the maximum value of the ArithmeticMethod enum.
46template <>
47struct Bottom<ArithmeticMethod>
48{
49 //! @brief Maximum value of the ArithmeticMethod enum.
50 static constexpr std::uint8_t value{4};
51};
52
53//! @brief Enumerate specific divisor methods.
54enum class DivisorMethod : std::uint8_t
55{
56 //! @brief Euclidean.
57 euclidean,
58 //! @brief Stein.
59 stein
60};
61//! @brief Store the maximum value of the DivisorMethod enum.
62template <>
63struct Bottom<DivisorMethod>
64{
65 //! @brief Maximum value of the DivisorMethod enum.
66 static constexpr std::uint8_t value{2};
67};
68
69//! @brief Enumerate specific integral methods.
70enum class IntegralMethod : std::uint8_t
71{
72 //! @brief Trapezoidal.
73 trapezoidal,
74 //! @brief Simpson.
75 simpson,
76 //! @brief Romberg.
77 romberg,
78 //! @brief Gauss.
79 gauss,
80 //! @brief Monte-Carlo.
81 monteCarlo
82};
83//! @brief Store the maximum value of the IntegralMethod enum.
84template <>
85struct Bottom<IntegralMethod>
86{
87 //! @brief Maximum value of the IntegralMethod enum.
88 static constexpr std::uint8_t value{5};
89};
90
91//! @brief Enumerate specific prime methods.
92enum class PrimeMethod : std::uint8_t
93{
94 //! @brief Eratosthenes.
95 eratosthenes,
96 //! @brief Euler.
97 euler
98};
99//! @brief Store the maximum value of the PrimeMethod enum.
100template <>
101struct Bottom<PrimeMethod>
102{
103 //! @brief Maximum value of the PrimeMethod enum.
104 static constexpr std::uint8_t value{2};
105};
106
107//! @brief Manage numeric choices.
108class ApplyNumeric
109{
110public:
111 //! @brief Enumerate specific numeric choices.
112 enum class Category : std::uint8_t
113 {
114 //! @brief Arithmetic.
115 arithmetic,
116 //! @brief Divisor.
117 divisor,
118 //! @brief Integral.
119 integral,
120 //! @brief Prime.
121 prime
122 };
123
124 //! @brief Bit flags for managing arithmetic methods.
125 std::bitset<Bottom<ArithmeticMethod>::value> arithmeticOpts;
126 //! @brief Bit flags for managing divisor methods.
127 std::bitset<Bottom<DivisorMethod>::value> divisorOpts;
128 //! @brief Bit flags for managing integral methods.
129 std::bitset<Bottom<IntegralMethod>::value> integralOpts;
130 //! @brief Bit flags for managing prime methods.
131 std::bitset<Bottom<PrimeMethod>::value> primeOpts;
132};
133
134//! @brief Manage the numeric choices.
135namespace manage
136{
137extern ApplyNumeric& choiceApplier();
138
139extern bool present();
140extern void clear();
141} // namespace manage
142
143//! @brief Constraint for numeric-registering.
144//! @tparam Meth - type of method
145template <typename Meth>
146concept Registrant = std::is_same_v<Meth, ArithmeticMethod> || std::is_same_v<Meth, DivisorMethod>
147 || std::is_same_v<Meth, IntegralMethod> || std::is_same_v<Meth, PrimeMethod>;
148//! @brief Set the choice.
149//! @tparam Meth - type of target method
150//! @param choice - target choice
151template <typename Meth>
152requires Registrant<Meth>
153void setChoice(const std::string& choice);
154//! @brief Run the candidates.
155//! @tparam Meth - type of target method
156//! @param candidates - container for the candidate target choices
157template <typename Meth>
158requires Registrant<Meth>
159void runCandidates(const std::vector<std::string>& candidates);
160
161//! @brief Register arithmetic.
162namespace arithmetic
163{
164extern const char* version() noexcept;
165} // namespace arithmetic
166template <>
167void setChoice<ArithmeticMethod>(const std::string& choice);
168template <>
169void runCandidates<ArithmeticMethod>(const std::vector<std::string>& candidates);
170
171//! @brief Register divisor.
172namespace divisor
173{
174extern const char* version() noexcept;
175} // namespace divisor
176template <>
177void setChoice<DivisorMethod>(const std::string& choice);
178template <>
179void runCandidates<DivisorMethod>(const std::vector<std::string>& candidates);
180
181//! @brief Register integral.
182namespace integral
183{
184extern const char* version() noexcept;
185} // namespace integral
186template <>
187void setChoice<IntegralMethod>(const std::string& choice);
188template <>
189void runCandidates<IntegralMethod>(const std::vector<std::string>& candidates);
190
191//! @brief Register prime.
192namespace prime
193{
194extern const char* version() noexcept;
195} // namespace prime
196template <>
197void setChoice<PrimeMethod>(const std::string& choice);
198template <>
199void runCandidates<PrimeMethod>(const std::vector<std::string>& candidates);
200} // namespace reg_num
201} // namespace application
202
203//! @brief Reflect the numeric category name and alias name to the field in the mapping.
204#define REG_NUM_REFLECT_FIRST_LEVEL_FIELD(category, alias) \
205 Field \
206 { \
207 REFLECTION_STR(MACRO_STRINGIFY(category)), &Type::MACRO_CONCAT(category, Opts), AttrList \
208 { \
209 Attr \
210 { \
211 REFLECTION_STR("alias"), MACRO_STRINGIFY(alias) \
212 } \
213 } \
214 }
215//! @brief Reflect the entry under the numeric category and choice name to the field in the mapping.
216#define REG_NUM_REFLECT_SECOND_LEVEL_FIELD(entry, choice) \
217 Field \
218 { \
219 REFLECTION_STR(MACRO_STRINGIFY(entry)), Type::entry, AttrList \
220 { \
221 Attr \
222 { \
223 REFLECTION_STR("choice"), MACRO_STRINGIFY(choice) \
224 } \
225 } \
226 }
227//! @brief Static reflection for ApplyNumeric. Used to map command line arguments.
228template <>
229struct utility::reflection::TypeInfo<application::reg_num::ApplyNumeric>
230 : public TypeInfoImpl<application::reg_num::ApplyNumeric>
231{
232 //! @brief Name.
233 static constexpr std::string_view name{"app-num"};
234 // clang-format off
235 //! @brief Field list.
236 static constexpr FieldList fields
237 {
238 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(arithmetic, a),
239 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(divisor , d),
240 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(integral , i),
241 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(prime , p),
242 };
243 // clang-format on
244 //! @brief Attribute list.
245 static constexpr AttrList attrs{Attr{REFLECTION_STR("descr"), "apply numeric"}};
246};
247//! @brief Static reflection for ArithmeticMethod. Used to map command line arguments.
248template <>
249struct utility::reflection::TypeInfo<application::reg_num::ArithmeticMethod>
250 : public TypeInfoImpl<application::reg_num::ArithmeticMethod>
251{
252 //! @brief Name.
253 static constexpr std::string_view name{"arithmetic"};
254 // clang-format off
255 //! @brief Field list.
256 static constexpr FieldList fields
257 {
258 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(addition , add),
259 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(subtraction , sub),
260 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(multiplication, mul),
261 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(division , div),
262 };
263 // clang-format on
264 //! @brief Attribute list.
265 static constexpr AttrList attrs{Attr{
266 REFLECTION_STR("descr"),
267 "arithmetic-related choices\n"
268 "- add Addition\n"
269 "- sub Subtraction\n"
270 "- mul Multiplication\n"
271 "- div Division\n"
272 "add the choices listed above"}};
273};
274//! @brief Static reflection for DivisorMethod. Used to map command line arguments.
275template <>
276struct utility::reflection::TypeInfo<application::reg_num::DivisorMethod>
277 : public TypeInfoImpl<application::reg_num::DivisorMethod>
278{
279 //! @brief Name.
280 static constexpr std::string_view name{"divisor"};
281 // clang-format off
282 //! @brief Field list.
283 static constexpr FieldList fields
284 {
285 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(euclidean, euc),
286 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(stein , ste),
287 };
288 // clang-format on
289 //! @brief Attribute list.
290 static constexpr AttrList attrs{Attr{
291 REFLECTION_STR("descr"),
292 "divisor-related choices\n"
293 "- euc Euclidean\n"
294 "- ste Stein\n"
295 "add the choices listed above"}};
296};
297//! @brief Static reflection for IntegralMethod. Used to map command line arguments.
298template <>
299struct utility::reflection::TypeInfo<application::reg_num::IntegralMethod>
300 : public TypeInfoImpl<application::reg_num::IntegralMethod>
301{
302 //! @brief Name.
303 static constexpr std::string_view name{"integral"};
304 // clang-format off
305 //! @brief Field list.
306 static constexpr FieldList fields
307 {
308 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(trapezoidal, tra),
309 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(simpson , sim),
310 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(romberg , rom),
311 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(gauss , gau),
312 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(monteCarlo , mon),
313 };
314 // clang-format on
315 //! @brief Attribute list.
316 static constexpr AttrList attrs{Attr{
317 REFLECTION_STR("descr"),
318 "integral-related choices\n"
319 "- tra Trapezoidal\n"
320 "- sim Adaptive Simpson's 1/3\n"
321 "- rom Romberg\n"
322 "- gau Gauss-Legendre's 5-Points\n"
323 "- mon Monte-Carlo\n"
324 "add the choices listed above"}};
325};
326//! @brief Static reflection for PrimeMethod. Used to map command line arguments.
327template <>
328struct utility::reflection::TypeInfo<application::reg_num::PrimeMethod>
329 : public TypeInfoImpl<application::reg_num::PrimeMethod>
330{
331 //! @brief Name.
332 static constexpr std::string_view name{"prime"};
333 // clang-format off
334 //! @brief Field list.
335 static constexpr FieldList fields
336 {
337 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(eratosthenes, era),
338 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(euler , eul),
339 };
340 // clang-format on
341 //! @brief Attribute list.
342 static constexpr AttrList attrs{Attr{
343 REFLECTION_STR("descr"),
344 "prime-related choices\n"
345 "- era Eratosthenes\n"
346 "- eul Euler\n"
347 "add the choices listed above"}};
348};
349#undef REG_NUM_REFLECT_FIRST_LEVEL_FIELD
350#undef REG_NUM_REFLECT_SECOND_LEVEL_FIELD
351
352namespace application::reg_num
353{
354//! @brief Alias for the type information.
355//! @tparam UDT - type of user defined data
356template <typename UDT>
357using TypeInfo = utility::reflection::TypeInfo<UDT>;
358//! @brief Alias for the category.
359using Category = ApplyNumeric::Category;
360//! @brief Convert category enumeration to string.
361//! @param cat - target category
362//! @return category name
363consteval std::string_view toString(const Category cat)
364{
365 switch (cat)
366 {
367 case Category::arithmetic:
368 return TypeInfo<ArithmeticMethod>::name;
369 case Category::divisor:
370 return TypeInfo<DivisorMethod>::name;
371 case Category::integral:
372 return TypeInfo<IntegralMethod>::name;
373 case Category::prime:
374 return TypeInfo<PrimeMethod>::name;
375 default:
376 break;
377 }
378 return {};
379}
380//! @brief Get the bit flags of the category in numeric choices.
381//! @tparam Cat - target category
382//! @return reference of the category bit flags
383template <Category Cat>
384constexpr auto& categoryOpts()
385{
386 return std::invoke(
387 TypeInfo<ApplyNumeric>::fields.find(REFLECTION_STR(toString(Cat))).value, manage::choiceApplier());
388}
389//! @brief The literal hash value of the abbreviation for the candidate method.
390//! @tparam Meth - type of candidate method
391//! @param method - candidate method
392//! @return literal hash value
393template <typename Meth>
394consteval std::size_t abbrLitHash(const Meth method)
395{
396 static_assert(Bottom<Meth>::value == TypeInfo<Meth>::fields.size);
397 constexpr auto refl = REFLECTION_STR("choice");
398 std::size_t value = 0;
399 TypeInfo<Meth>::fields.findIf(
400 [refl, method, &value](const auto field)
401 {
402 if (field.name == TypeInfo<Meth>::fields.nameOfValue(method))
403 {
404 static_assert(field.attrs.contains(refl) && (field.attrs.size == 1));
405 const auto attr = field.attrs.find(refl);
406 static_assert(attr.hasValue);
407 value = utility::common::operator""_bkdrHash(attr.value);
408 return true;
409 }
410 return false;
411 });
412 return value;
413}
414} // namespace application::reg_num
415