1//! @file apply_data_structure.cpp
2//! @author ryftchen
3//! @brief The definitions (apply_data_structure) in the application module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#include "apply_data_structure.hpp"
8#include "register_data_structure.hpp"
9
10#ifndef _PRECOMPILED_HEADER
11#include <iomanip>
12#include <ranges>
13#else
14#include "application/pch/precompiled_header.hpp"
15#endif
16
17#include "application/core/include/log.hpp"
18#include "utility/include/currying.hpp"
19
20//! @brief Title of printing when data structure tasks are beginning.
21#define APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title) \
22 std::osyncstream(std::cout) << "\nAPPLY DATA STRUCTURE: " << std::setiosflags(std::ios_base::left) \
23 << std::setfill('.') << std::setw(50) << (title) << "BEGIN" \
24 << std::resetiosflags(std::ios_base::left) << std::setfill(' ') << std::endl; \
25 {
26//! @brief Title of printing when data structure tasks are ending.
27#define APP_DS_PRINT_TASK_TITLE_SCOPE_END(title) \
28 } \
29 std::osyncstream(std::cout) << "\nAPPLY DATA STRUCTURE: " << std::setiosflags(std::ios_base::left) \
30 << std::setfill('.') << std::setw(50) << (title) << "END" \
31 << std::resetiosflags(std::ios_base::left) << std::setfill(' ') << '\n' \
32 << std::endl;
33
34namespace application::app_ds
35{
36using namespace reg_ds; // NOLINT(google-build-using-namespace)
37
38//! @brief Make the title of a particular instance in data structure choices.
39//! @tparam Inst - type of target instance
40//! @param instance - target instance
41//! @return initial capitalized title
42template <typename Inst>
43static std::string customTitle(const Inst instance)
44{
45 std::string title(TypeInfo<Inst>::fields.nameOfValue(instance));
46 title.at(n: 0) = static_cast<char>(std::toupper(c: title.at(n: 0)));
47 return title;
48}
49
50//! @brief Get the curried task name.
51//! @return curried task name
52static const auto& curriedTaskName()
53{
54 static const auto curried =
55 utility::currying::curry(func: configure::task::presetName, args: TypeInfo<ApplyDataStructure>::name);
56 return curried;
57}
58
59//! @brief Get the alias of the category in data structure choices.
60//! @tparam Cat - target category
61//! @return alias of the category name
62template <Category Cat>
63static consteval std::string_view categoryAlias()
64{
65 constexpr auto attr =
66 TypeInfo<ApplyDataStructure>::fields.find(REFLECTION_STR(toString(Cat))).attrs.find(REFLECTION_STR("alias"));
67 static_assert(attr.hasValue);
68 return attr.value;
69}
70
71namespace cache
72{
73//! @brief Show the contents of the cache result.
74//! @param instance - used cache instance
75//! @param result - cache result
76static void display(const CacheInstance instance, const std::string& result)
77{
78 std::printf(format: "\n==> %-19s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
79}
80
81//! @brief Structure of cache.
82//! @param instance - used cache instance
83static void structure(const CacheInstance instance)
84try
85{
86 std::ostringstream result{};
87 switch (instance)
88 {
89 static_assert(utility::common::isStatelessClass<Showcase>());
90 case CacheInstance::firstInFirstOut:
91 result = Showcase::fifo();
92 break;
93 case CacheInstance::leastFrequentlyUsed:
94 result = Showcase::lfu();
95 break;
96 case CacheInstance::leastRecentlyUsed:
97 result = Showcase::lru();
98 break;
99 default:
100 return;
101 }
102 display(instance, result: result.str());
103}
104catch (const std::exception& err)
105{
106 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
107}
108} // namespace cache
109//! @brief To apply cache-related instances that are mapped to choices.
110//! @param candidates - container for the candidate target choices
111void applyingCache(const std::vector<std::string>& candidates)
112{
113 constexpr auto category = Category::cache;
114 const auto& spec = categoryOpts<category>();
115 if (MACRO_IMPLIES(spec.any(), spec.size() != candidates.size()))
116 {
117 return;
118 }
119
120 const std::string_view title = data_structure::cache::description();
121 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
122
123 auto& pooling = configure::task::resourcePool();
124 auto* const allocatedJob = pooling.newEntry(args: spec.count());
125 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
126 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subtask, const CacheInstance instance)
127 { allocatedJob->enqueue(name: taskNamer(subtask), func&: cache::structure, args: instance); };
128 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
129
130 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
131 for (const auto index :
132 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
133 {
134 const auto& choice = candidates.at(n: index);
135 switch (utility::common::bkdrHash(str: choice.c_str()))
136 {
137 case abbrLitHash(instance: CacheInstance::firstInFirstOut):
138 addTask(choice, CacheInstance::firstInFirstOut);
139 break;
140 case abbrLitHash(instance: CacheInstance::leastFrequentlyUsed):
141 addTask(choice, CacheInstance::leastFrequentlyUsed);
142 break;
143 case abbrLitHash(instance: CacheInstance::leastRecentlyUsed):
144 addTask(choice, CacheInstance::leastRecentlyUsed);
145 break;
146 default:
147 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
148 }
149 }
150
151 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
152}
153
154namespace filter
155{
156//! @brief Show the contents of the filter result.
157//! @param instance - used filter instance
158//! @param result - filter result
159static void display(const FilterInstance instance, const std::string& result)
160{
161 std::printf(format: "\n==> %-8s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
162}
163
164//! @brief Structure of filter.
165//! @param instance - used filter instance
166static void structure(const FilterInstance instance)
167try
168{
169 std::ostringstream result{};
170 switch (instance)
171 {
172 static_assert(utility::common::isStatelessClass<Showcase>());
173 case FilterInstance::bloom:
174 result = Showcase::bloom();
175 break;
176 case FilterInstance::quotient:
177 result = Showcase::quotient();
178 break;
179 default:
180 return;
181 }
182 display(instance, result: result.str());
183}
184catch (const std::exception& err)
185{
186 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
187}
188} // namespace filter
189//! @brief To apply filter-related instances that are mapped to choices.
190//! @param candidates - container for the candidate target choices
191void applyingFilter(const std::vector<std::string>& candidates)
192{
193 constexpr auto category = Category::filter;
194 const auto& spec = categoryOpts<category>();
195 if (MACRO_IMPLIES(spec.any(), spec.size() != candidates.size()))
196 {
197 return;
198 }
199
200 const std::string_view title = data_structure::filter::description();
201 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
202
203 auto& pooling = configure::task::resourcePool();
204 auto* const allocatedJob = pooling.newEntry(args: spec.count());
205 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
206 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subtask, const FilterInstance instance)
207 { allocatedJob->enqueue(name: taskNamer(subtask), func&: filter::structure, args: instance); };
208 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
209
210 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
211 for (const auto index :
212 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
213 {
214 const auto& choice = candidates.at(n: index);
215 switch (utility::common::bkdrHash(str: choice.c_str()))
216 {
217 case abbrLitHash(instance: FilterInstance::bloom):
218 addTask(choice, FilterInstance::bloom);
219 break;
220 case abbrLitHash(instance: FilterInstance::quotient):
221 addTask(choice, FilterInstance::quotient);
222 break;
223 default:
224 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
225 }
226 }
227
228 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
229}
230
231namespace graph
232{
233//! @brief Show the contents of the graph result.
234//! @param instance - used graph instance
235//! @param result - graph result
236static void display(const GraphInstance instance, const std::string& result)
237{
238 std::printf(format: "\n==> %-10s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
239}
240
241//! @brief Structure of graph.
242//! @param instance - used graph instance
243static void structure(const GraphInstance instance)
244try
245{
246 std::ostringstream result{};
247 switch (instance)
248 {
249 static_assert(utility::common::isStatelessClass<Showcase>());
250 case GraphInstance::undirected:
251 result = Showcase::undirected();
252 break;
253 case GraphInstance::directed:
254 result = Showcase::directed();
255 break;
256 default:
257 return;
258 }
259 display(instance, result: result.str());
260}
261catch (const std::exception& err)
262{
263 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
264}
265} // namespace graph
266//! @brief To apply graph-related instances that are mapped to choices.
267//! @param candidates - container for the candidate target choices
268void applyingGraph(const std::vector<std::string>& candidates)
269{
270 constexpr auto category = Category::graph;
271 const auto& spec = categoryOpts<category>();
272 if (MACRO_IMPLIES(spec.any(), spec.size() != candidates.size()))
273 {
274 return;
275 }
276
277 const std::string_view title = data_structure::graph::description();
278 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
279
280 auto& pooling = configure::task::resourcePool();
281 auto* const allocatedJob = pooling.newEntry(args: spec.count());
282 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
283 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subtask, const GraphInstance instance)
284 { allocatedJob->enqueue(name: taskNamer(subtask), func&: graph::structure, args: instance); };
285 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
286
287 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
288 for (const auto index :
289 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
290 {
291 const auto& choice = candidates.at(n: index);
292 switch (utility::common::bkdrHash(str: choice.c_str()))
293 {
294 case abbrLitHash(instance: GraphInstance::undirected):
295 addTask(choice, GraphInstance::undirected);
296 break;
297 case abbrLitHash(instance: GraphInstance::directed):
298 addTask(choice, GraphInstance::directed);
299 break;
300 default:
301 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
302 }
303 }
304
305 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
306}
307
308namespace heap
309{
310//! @brief Show the contents of the heap result.
311//! @param instance - used heap instance
312//! @param result - heap result
313static void display(const HeapInstance instance, const std::string& result)
314{
315 std::printf(format: "\n==> %-7s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
316}
317
318//! @brief Structure of heap.
319//! @param instance - used heap instance
320static void structure(const HeapInstance instance)
321try
322{
323 std::ostringstream result{};
324 switch (instance)
325 {
326 static_assert(utility::common::isStatelessClass<Showcase>());
327 case HeapInstance::binary:
328 result = Showcase::binary();
329 break;
330 case HeapInstance::leftist:
331 result = Showcase::leftist();
332 break;
333 case HeapInstance::skew:
334 result = Showcase::skew();
335 break;
336 default:
337 return;
338 }
339 display(instance, result: result.str());
340}
341catch (const std::exception& err)
342{
343 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
344}
345} // namespace heap
346//! @brief To apply heap-related instances that are mapped to choices.
347//! @param candidates - container for the candidate target choices
348void applyingHeap(const std::vector<std::string>& candidates)
349{
350 constexpr auto category = Category::heap;
351 const auto& spec = categoryOpts<category>();
352 if (MACRO_IMPLIES(spec.any(), spec.size() != candidates.size()))
353 {
354 return;
355 }
356
357 const std::string_view title = data_structure::heap::description();
358 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
359
360 auto& pooling = configure::task::resourcePool();
361 auto* const allocatedJob = pooling.newEntry(args: spec.count());
362 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
363 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subtask, const HeapInstance instance)
364 { allocatedJob->enqueue(name: taskNamer(subtask), func&: heap::structure, args: instance); };
365 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
366
367 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
368 for (const auto index :
369 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
370 {
371 const auto& choice = candidates.at(n: index);
372 switch (utility::common::bkdrHash(str: choice.c_str()))
373 {
374 case abbrLitHash(instance: HeapInstance::binary):
375 addTask(choice, HeapInstance::binary);
376 break;
377 case abbrLitHash(instance: HeapInstance::leftist):
378 addTask(choice, HeapInstance::leftist);
379 break;
380 case abbrLitHash(instance: HeapInstance::skew):
381 addTask(choice, HeapInstance::skew);
382 break;
383 default:
384 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
385 }
386 }
387
388 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
389}
390
391namespace linear
392{
393//! @brief Show the contents of the linear result.
394//! @param instance - used linear instance
395//! @param result - linear result
396static void display(const LinearInstance instance, const std::string& result)
397{
398 std::printf(format: "\n==> %-16s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
399}
400
401//! @brief Structure of linear.
402//! @param instance - used linear instance
403static void structure(const LinearInstance instance)
404try
405{
406 std::ostringstream result{};
407 switch (instance)
408 {
409 static_assert(utility::common::isStatelessClass<Showcase>());
410 case LinearInstance::doublyLinkedList:
411 result = Showcase::dll();
412 break;
413 case LinearInstance::stack:
414 result = Showcase::stack();
415 break;
416 case LinearInstance::queue:
417 result = Showcase::queue();
418 break;
419 default:
420 return;
421 }
422 display(instance, result: result.str());
423}
424catch (const std::exception& err)
425{
426 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
427}
428} // namespace linear
429//! @brief To apply linear-related instances that are mapped to choices.
430//! @param candidates - container for the candidate target choices
431void applyingLinear(const std::vector<std::string>& candidates)
432{
433 constexpr auto category = Category::linear;
434 const auto& spec = categoryOpts<category>();
435 if (MACRO_IMPLIES(spec.any(), spec.size() != candidates.size()))
436 {
437 return;
438 }
439
440 const std::string_view title = data_structure::linear::description();
441 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
442
443 auto& pooling = configure::task::resourcePool();
444 auto* const allocatedJob = pooling.newEntry(args: spec.count());
445 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
446 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subtask, const LinearInstance instance)
447 { allocatedJob->enqueue(name: taskNamer(subtask), func&: linear::structure, args: instance); };
448 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
449
450 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
451 for (const auto index :
452 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
453 {
454 const auto& choice = candidates.at(n: index);
455 switch (utility::common::bkdrHash(str: choice.c_str()))
456 {
457 case abbrLitHash(instance: LinearInstance::doublyLinkedList):
458 addTask(choice, LinearInstance::doublyLinkedList);
459 break;
460 case abbrLitHash(instance: LinearInstance::stack):
461 addTask(choice, LinearInstance::stack);
462 break;
463 case abbrLitHash(instance: LinearInstance::queue):
464 addTask(choice, LinearInstance::queue);
465 break;
466 default:
467 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
468 }
469 }
470
471 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
472}
473
474namespace tree
475{
476//! @brief Show the contents of the tree result.
477//! @param instance - used tree instance
478//! @param result - tree result
479static void display(const TreeInstance instance, const std::string& result)
480{
481 std::printf(format: "\n==> %-19s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
482}
483
484//! @brief Structure of tree.
485//! @param instance - used tree instance
486static void structure(const TreeInstance instance)
487try
488{
489 std::ostringstream result{};
490 switch (instance)
491 {
492 static_assert(utility::common::isStatelessClass<Showcase>());
493 case TreeInstance::binarySearch:
494 result = Showcase::bs();
495 break;
496 case TreeInstance::adelsonVelskyLandis:
497 result = Showcase::avl();
498 break;
499 case TreeInstance::splay:
500 result = Showcase::splay();
501 break;
502 default:
503 return;
504 }
505 display(instance, result: result.str());
506}
507catch (const std::exception& err)
508{
509 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
510}
511} // namespace tree
512//! @brief To apply tree-related instances that are mapped to choices.
513//! @param candidates - container for the candidate target choices
514void applyingTree(const std::vector<std::string>& candidates)
515{
516 constexpr auto category = Category::tree;
517 const auto& spec = categoryOpts<category>();
518 if (MACRO_IMPLIES(spec.any(), spec.size() != candidates.size()))
519 {
520 return;
521 }
522
523 const std::string_view title = data_structure::tree::description();
524 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
525
526 auto& pooling = configure::task::resourcePool();
527 auto* const allocatedJob = pooling.newEntry(args: spec.count());
528 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
529 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subtask, const TreeInstance instance)
530 { allocatedJob->enqueue(name: taskNamer(subtask), func&: tree::structure, args: instance); };
531 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
532
533 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
534 for (const auto index :
535 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
536 {
537 const auto& choice = candidates.at(n: index);
538 switch (utility::common::bkdrHash(str: choice.c_str()))
539 {
540 case abbrLitHash(instance: TreeInstance::binarySearch):
541 addTask(choice, TreeInstance::binarySearch);
542 break;
543 case abbrLitHash(instance: TreeInstance::adelsonVelskyLandis):
544 addTask(choice, TreeInstance::adelsonVelskyLandis);
545 break;
546 case abbrLitHash(instance: TreeInstance::splay):
547 addTask(choice, TreeInstance::splay);
548 break;
549 default:
550 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
551 }
552 }
553
554 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
555}
556} // namespace application::app_ds
557
558#undef APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN
559#undef APP_DS_PRINT_TASK_TITLE_SCOPE_END
560