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-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 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 Set choice.
144//! @tparam Meth - type of target method
145//! @param choice - target choice
146template <typename Meth>
147void setChoice(const std::string& choice);
148//! @brief Run candidates.
149//! @tparam Meth - type of target method
150//! @param candidates - container for the candidate target choices
151template <typename Meth>
152void runCandidates(const std::vector<std::string>& candidates);
153
154//! @brief Register arithmetic.
155namespace arithmetic
156{
157extern const char* version() noexcept;
158} // namespace arithmetic
159template <>
160void setChoice<ArithmeticMethod>(const std::string& choice);
161template <>
162void runCandidates<ArithmeticMethod>(const std::vector<std::string>& candidates);
163
164//! @brief Register divisor.
165namespace divisor
166{
167extern const char* version() noexcept;
168} // namespace divisor
169template <>
170void setChoice<DivisorMethod>(const std::string& choice);
171template <>
172void runCandidates<DivisorMethod>(const std::vector<std::string>& candidates);
173
174//! @brief Register integral.
175namespace integral
176{
177extern const char* version() noexcept;
178} // namespace integral
179template <>
180void setChoice<IntegralMethod>(const std::string& choice);
181template <>
182void runCandidates<IntegralMethod>(const std::vector<std::string>& candidates);
183
184//! @brief Register prime.
185namespace prime
186{
187extern const char* version() noexcept;
188} // namespace prime
189template <>
190void setChoice<PrimeMethod>(const std::string& choice);
191template <>
192void runCandidates<PrimeMethod>(const std::vector<std::string>& candidates);
193} // namespace reg_num
194} // namespace application
195
196//! @brief Reflect the numeric category name and alias name to the field in the mapping.
197#define REG_NUM_REFLECT_FIRST_LEVEL_FIELD(category, alias) \
198 Field \
199 { \
200 REFLECTION_STR(MACRO_STRINGIFY(category)), &Type::MACRO_CONCAT(category, Opts), AttrList \
201 { \
202 Attr \
203 { \
204 REFLECTION_STR("alias"), MACRO_STRINGIFY(alias) \
205 } \
206 } \
207 }
208//! @brief Reflect the entry under the numeric category and choice name to the field in the mapping.
209#define REG_NUM_REFLECT_SECOND_LEVEL_FIELD(entry, choice) \
210 Field \
211 { \
212 REFLECTION_STR(MACRO_STRINGIFY(entry)), Type::entry, AttrList \
213 { \
214 Attr \
215 { \
216 REFLECTION_STR("choice"), MACRO_STRINGIFY(choice) \
217 } \
218 } \
219 }
220//! @brief Static reflection for ApplyNumeric. Used to map command line arguments.
221template <>
222struct utility::reflection::TypeInfo<application::reg_num::ApplyNumeric>
223 : public TypeInfoImpl<application::reg_num::ApplyNumeric>
224{
225 //! @brief Name.
226 static constexpr std::string_view name{"app-num"};
227 // clang-format off
228 //! @brief Field list.
229 static constexpr FieldList fields
230 {
231 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(arithmetic, a),
232 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(divisor , d),
233 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(integral , i),
234 REG_NUM_REFLECT_FIRST_LEVEL_FIELD(prime , p),
235 };
236 // clang-format on
237 //! @brief Attribute list.
238 static constexpr AttrList attrs{Attr{REFLECTION_STR("descr"), "apply numeric"}};
239};
240//! @brief Static reflection for ArithmeticMethod. Used to map command line arguments.
241template <>
242struct utility::reflection::TypeInfo<application::reg_num::ArithmeticMethod>
243 : public TypeInfoImpl<application::reg_num::ArithmeticMethod>
244{
245 //! @brief Name.
246 static constexpr std::string_view name{"arithmetic"};
247 // clang-format off
248 //! @brief Field list.
249 static constexpr FieldList fields
250 {
251 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(addition , add),
252 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(subtraction , sub),
253 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(multiplication, mul),
254 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(division , div),
255 };
256 // clang-format on
257 //! @brief Attribute list.
258 static constexpr AttrList attrs{Attr{
259 REFLECTION_STR("descr"),
260 "arithmetic-related choices\n"
261 "- add Addition\n"
262 "- sub Subtraction\n"
263 "- mul Multiplication\n"
264 "- div Division\n"
265 "add the choices listed above"}};
266};
267//! @brief Static reflection for DivisorMethod. Used to map command line arguments.
268template <>
269struct utility::reflection::TypeInfo<application::reg_num::DivisorMethod>
270 : public TypeInfoImpl<application::reg_num::DivisorMethod>
271{
272 //! @brief Name.
273 static constexpr std::string_view name{"divisor"};
274 // clang-format off
275 //! @brief Field list.
276 static constexpr FieldList fields
277 {
278 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(euclidean, euc),
279 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(stein , ste),
280 };
281 // clang-format on
282 //! @brief Attribute list.
283 static constexpr AttrList attrs{Attr{
284 REFLECTION_STR("descr"),
285 "divisor-related choices\n"
286 "- euc Euclidean\n"
287 "- ste Stein\n"
288 "add the choices listed above"}};
289};
290//! @brief Static reflection for IntegralMethod. Used to map command line arguments.
291template <>
292struct utility::reflection::TypeInfo<application::reg_num::IntegralMethod>
293 : public TypeInfoImpl<application::reg_num::IntegralMethod>
294{
295 //! @brief Name.
296 static constexpr std::string_view name{"integral"};
297 // clang-format off
298 //! @brief Field list.
299 static constexpr FieldList fields
300 {
301 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(trapezoidal, tra),
302 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(simpson , sim),
303 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(romberg , rom),
304 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(gauss , gau),
305 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(monteCarlo , mon),
306 };
307 // clang-format on
308 //! @brief Attribute list.
309 static constexpr AttrList attrs{Attr{
310 REFLECTION_STR("descr"),
311 "integral-related choices\n"
312 "- tra Trapezoidal\n"
313 "- sim Adaptive Simpson's 1/3\n"
314 "- rom Romberg\n"
315 "- gau Gauss-Legendre's 5-Points\n"
316 "- mon Monte-Carlo\n"
317 "add the choices listed above"}};
318};
319//! @brief Static reflection for PrimeMethod. Used to map command line arguments.
320template <>
321struct utility::reflection::TypeInfo<application::reg_num::PrimeMethod>
322 : public TypeInfoImpl<application::reg_num::PrimeMethod>
323{
324 //! @brief Name.
325 static constexpr std::string_view name{"prime"};
326 // clang-format off
327 //! @brief Field list.
328 static constexpr FieldList fields
329 {
330 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(eratosthenes, era),
331 REG_NUM_REFLECT_SECOND_LEVEL_FIELD(euler , eul),
332 };
333 // clang-format on
334 //! @brief Attribute list.
335 static constexpr AttrList attrs{Attr{
336 REFLECTION_STR("descr"),
337 "prime-related choices\n"
338 "- era Eratosthenes\n"
339 "- eul Euler\n"
340 "add the choices listed above"}};
341};
342#undef REG_NUM_REFLECT_FIRST_LEVEL_FIELD
343#undef REG_NUM_REFLECT_SECOND_LEVEL_FIELD
344
345namespace application::reg_num
346{
347//! @brief Alias for the type information.
348//! @tparam UDT - type of user defined data
349template <typename UDT>
350using TypeInfo = utility::reflection::TypeInfo<UDT>;
351//! @brief Alias for the category.
352using Category = ApplyNumeric::Category;
353//! @brief Convert category enumeration to string.
354//! @param cat - target category
355//! @return category name
356consteval std::string_view toString(const Category cat)
357{
358 switch (cat)
359 {
360 case Category::arithmetic:
361 return TypeInfo<ArithmeticMethod>::name;
362 case Category::divisor:
363 return TypeInfo<DivisorMethod>::name;
364 case Category::integral:
365 return TypeInfo<IntegralMethod>::name;
366 case Category::prime:
367 return TypeInfo<PrimeMethod>::name;
368 default:
369 break;
370 }
371 return {};
372}
373//! @brief Get the bit flags of the category in numeric choices.
374//! @tparam Cat - target category
375//! @return reference of the category bit flags
376template <Category Cat>
377constexpr auto& categoryOpts()
378{
379 return std::invoke(
380 TypeInfo<ApplyNumeric>::fields.find(REFLECTION_STR(toString(Cat))).value, manage::choiceApplier());
381}
382//! @brief The literal hash value of the abbreviation for the candidate method.
383//! @tparam Meth - type of candidate method
384//! @param method - candidate method
385//! @return literal hash value
386template <typename Meth>
387consteval std::size_t abbrLitHash(const Meth method)
388{
389 static_assert(Bottom<Meth>::value == TypeInfo<Meth>::fields.size);
390 constexpr auto refl = REFLECTION_STR("choice");
391 std::size_t value = 0;
392 TypeInfo<Meth>::fields.findIf(
393 [refl, method, &value](const auto field)
394 {
395 if (field.name == TypeInfo<Meth>::fields.nameOfValue(method))
396 {
397 static_assert(field.attrs.contains(refl) && (field.attrs.size == 1));
398 const auto attr = field.attrs.find(refl);
399 static_assert(attr.hasValue);
400 value = utility::common::operator""_bkdrHash(attr.value);
401 return true;
402 }
403 return false;
404 });
405 return value;
406}
407} // namespace application::reg_num
408