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-2025 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 // _PRECOMPILED_HEADER
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) = 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 (spec.none())
116 {
117 return;
118 }
119 MACRO_ASSERT(spec.size() == candidates.size());
120
121 const std::string_view title = data_structure::cache::description();
122 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
123
124 auto& pooling = configure::task::resourcePool();
125 auto* const allocatedJob = pooling.newEntry(args: spec.count());
126 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
127 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subTask, const CacheInstance instance)
128 { allocatedJob->enqueue(name: taskNamer(subTask), func&: cache::structure, args: instance); };
129 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
130
131 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
132 for (const auto index :
133 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
134 {
135 const auto& choice = candidates.at(n: index);
136 switch (utility::common::bkdrHash(str: choice.c_str()))
137 {
138 case abbrLitHash(instance: CacheInstance::firstInFirstOut):
139 addTask(choice, CacheInstance::firstInFirstOut);
140 break;
141 case abbrLitHash(instance: CacheInstance::leastFrequentlyUsed):
142 addTask(choice, CacheInstance::leastFrequentlyUsed);
143 break;
144 case abbrLitHash(instance: CacheInstance::leastRecentlyUsed):
145 addTask(choice, CacheInstance::leastRecentlyUsed);
146 break;
147 default:
148 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
149 }
150 }
151
152 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
153}
154
155namespace filter
156{
157//! @brief Show the contents of the filter result.
158//! @param instance - used filter instance
159//! @param result - filter result
160static void display(const FilterInstance instance, const std::string& result)
161{
162 std::printf(format: "\n==> %-8s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
163}
164
165//! @brief Structure of filter.
166//! @param instance - used filter instance
167static void structure(const FilterInstance instance)
168try
169{
170 std::ostringstream result{};
171 switch (instance)
172 {
173 static_assert(utility::common::isStatelessClass<Showcase>());
174 case FilterInstance::bloom:
175 result = Showcase().bloom();
176 break;
177 case FilterInstance::quotient:
178 result = Showcase().quotient();
179 break;
180 default:
181 return;
182 }
183 display(instance, result: result.str());
184}
185catch (const std::exception& err)
186{
187 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
188}
189} // namespace filter
190//! @brief To apply filter-related instances that are mapped to choices.
191//! @param candidates - container for the candidate target choices
192void applyingFilter(const std::vector<std::string>& candidates)
193{
194 constexpr auto category = Category::filter;
195 const auto& spec = categoryOpts<category>();
196 if (spec.none())
197 {
198 return;
199 }
200 MACRO_ASSERT(spec.size() == candidates.size());
201
202 const std::string_view title = data_structure::filter::description();
203 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
204
205 auto& pooling = configure::task::resourcePool();
206 auto* const allocatedJob = pooling.newEntry(args: spec.count());
207 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
208 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subTask, const FilterInstance instance)
209 { allocatedJob->enqueue(name: taskNamer(subTask), func&: filter::structure, args: instance); };
210 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
211
212 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
213 for (const auto index :
214 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
215 {
216 const auto& choice = candidates.at(n: index);
217 switch (utility::common::bkdrHash(str: choice.c_str()))
218 {
219 case abbrLitHash(instance: FilterInstance::bloom):
220 addTask(choice, FilterInstance::bloom);
221 break;
222 case abbrLitHash(instance: FilterInstance::quotient):
223 addTask(choice, FilterInstance::quotient);
224 break;
225 default:
226 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
227 }
228 }
229
230 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
231}
232
233namespace graph
234{
235//! @brief Show the contents of the graph result.
236//! @param instance - used graph instance
237//! @param result - graph result
238static void display(const GraphInstance instance, const std::string& result)
239{
240 std::printf(format: "\n==> %-10s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
241}
242
243//! @brief Structure of graph.
244//! @param instance - used graph instance
245static void structure(const GraphInstance instance)
246try
247{
248 std::ostringstream result{};
249 switch (instance)
250 {
251 static_assert(utility::common::isStatelessClass<Showcase>());
252 case GraphInstance::undirected:
253 result = Showcase().undirected();
254 break;
255 case GraphInstance::directed:
256 result = Showcase().directed();
257 break;
258 default:
259 return;
260 }
261 display(instance, result: result.str());
262}
263catch (const std::exception& err)
264{
265 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
266}
267} // namespace graph
268//! @brief To apply graph-related instances that are mapped to choices.
269//! @param candidates - container for the candidate target choices
270void applyingGraph(const std::vector<std::string>& candidates)
271{
272 constexpr auto category = Category::graph;
273 const auto& spec = categoryOpts<category>();
274 if (spec.none())
275 {
276 return;
277 }
278 MACRO_ASSERT(spec.size() == candidates.size());
279
280 const std::string_view title = data_structure::graph::description();
281 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
282
283 auto& pooling = configure::task::resourcePool();
284 auto* const allocatedJob = pooling.newEntry(args: spec.count());
285 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
286 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subTask, const GraphInstance instance)
287 { allocatedJob->enqueue(name: taskNamer(subTask), func&: graph::structure, args: instance); };
288 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
289
290 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
291 for (const auto index :
292 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
293 {
294 const auto& choice = candidates.at(n: index);
295 switch (utility::common::bkdrHash(str: choice.c_str()))
296 {
297 case abbrLitHash(instance: GraphInstance::undirected):
298 addTask(choice, GraphInstance::undirected);
299 break;
300 case abbrLitHash(instance: GraphInstance::directed):
301 addTask(choice, GraphInstance::directed);
302 break;
303 default:
304 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
305 }
306 }
307
308 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
309}
310
311namespace heap
312{
313//! @brief Show the contents of the heap result.
314//! @param instance - used heap instance
315//! @param result - heap result
316static void display(const HeapInstance instance, const std::string& result)
317{
318 std::printf(format: "\n==> %-7s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
319}
320
321//! @brief Structure of heap.
322//! @param instance - used heap instance
323static void structure(const HeapInstance instance)
324try
325{
326 std::ostringstream result{};
327 switch (instance)
328 {
329 static_assert(utility::common::isStatelessClass<Showcase>());
330 case HeapInstance::binary:
331 result = Showcase().binary();
332 break;
333 case HeapInstance::leftist:
334 result = Showcase().leftist();
335 break;
336 case HeapInstance::skew:
337 result = Showcase().skew();
338 break;
339 default:
340 return;
341 }
342 display(instance, result: result.str());
343}
344catch (const std::exception& err)
345{
346 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
347}
348} // namespace heap
349//! @brief To apply heap-related instances that are mapped to choices.
350//! @param candidates - container for the candidate target choices
351void applyingHeap(const std::vector<std::string>& candidates)
352{
353 constexpr auto category = Category::heap;
354 const auto& spec = categoryOpts<category>();
355 if (spec.none())
356 {
357 return;
358 }
359 MACRO_ASSERT(spec.size() == candidates.size());
360
361 const std::string_view title = data_structure::heap::description();
362 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
363
364 auto& pooling = configure::task::resourcePool();
365 auto* const allocatedJob = pooling.newEntry(args: spec.count());
366 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
367 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subTask, const HeapInstance instance)
368 { allocatedJob->enqueue(name: taskNamer(subTask), func&: heap::structure, args: instance); };
369 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
370
371 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
372 for (const auto index :
373 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
374 {
375 const auto& choice = candidates.at(n: index);
376 switch (utility::common::bkdrHash(str: choice.c_str()))
377 {
378 case abbrLitHash(instance: HeapInstance::binary):
379 addTask(choice, HeapInstance::binary);
380 break;
381 case abbrLitHash(instance: HeapInstance::leftist):
382 addTask(choice, HeapInstance::leftist);
383 break;
384 case abbrLitHash(instance: HeapInstance::skew):
385 addTask(choice, HeapInstance::skew);
386 break;
387 default:
388 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
389 }
390 }
391
392 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
393}
394
395namespace linear
396{
397//! @brief Show the contents of the linear result.
398//! @param instance - used linear instance
399//! @param result - linear result
400static void display(const LinearInstance instance, const std::string& result)
401{
402 std::printf(format: "\n==> %-16s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
403}
404
405//! @brief Structure of linear.
406//! @param instance - used linear instance
407static void structure(const LinearInstance instance)
408try
409{
410 std::ostringstream result{};
411 switch (instance)
412 {
413 static_assert(utility::common::isStatelessClass<Showcase>());
414 case LinearInstance::doublyLinkedList:
415 result = Showcase().dll();
416 break;
417 case LinearInstance::stack:
418 result = Showcase().stack();
419 break;
420 case LinearInstance::queue:
421 result = Showcase().queue();
422 break;
423 default:
424 return;
425 }
426 display(instance, result: result.str());
427}
428catch (const std::exception& err)
429{
430 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
431}
432} // namespace linear
433//! @brief To apply linear-related instances that are mapped to choices.
434//! @param candidates - container for the candidate target choices
435void applyingLinear(const std::vector<std::string>& candidates)
436{
437 constexpr auto category = Category::linear;
438 const auto& spec = categoryOpts<category>();
439 if (spec.none())
440 {
441 return;
442 }
443 MACRO_ASSERT(spec.size() == candidates.size());
444
445 const std::string_view title = data_structure::linear::description();
446 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
447
448 auto& pooling = configure::task::resourcePool();
449 auto* const allocatedJob = pooling.newEntry(args: spec.count());
450 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
451 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subTask, const LinearInstance instance)
452 { allocatedJob->enqueue(name: taskNamer(subTask), func&: linear::structure, args: instance); };
453 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
454
455 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
456 for (const auto index :
457 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
458 {
459 const auto& choice = candidates.at(n: index);
460 switch (utility::common::bkdrHash(str: choice.c_str()))
461 {
462 case abbrLitHash(instance: LinearInstance::doublyLinkedList):
463 addTask(choice, LinearInstance::doublyLinkedList);
464 break;
465 case abbrLitHash(instance: LinearInstance::stack):
466 addTask(choice, LinearInstance::stack);
467 break;
468 case abbrLitHash(instance: LinearInstance::queue):
469 addTask(choice, LinearInstance::queue);
470 break;
471 default:
472 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
473 }
474 }
475
476 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
477}
478
479namespace tree
480{
481//! @brief Show the contents of the tree result.
482//! @param instance - used tree instance
483//! @param result - tree result
484static void display(const TreeInstance instance, const std::string& result)
485{
486 std::printf(format: "\n==> %-19s Instance <==\n%s", customTitle(instance).c_str(), result.c_str());
487}
488
489//! @brief Structure of tree.
490//! @param instance - used tree instance
491static void structure(const TreeInstance instance)
492try
493{
494 std::ostringstream result{};
495 switch (instance)
496 {
497 static_assert(utility::common::isStatelessClass<Showcase>());
498 case TreeInstance::binarySearch:
499 result = Showcase().bs();
500 break;
501 case TreeInstance::adelsonVelskyLandis:
502 result = Showcase().avl();
503 break;
504 case TreeInstance::splay:
505 result = Showcase().splay();
506 break;
507 default:
508 return;
509 }
510 display(instance, result: result.str());
511}
512catch (const std::exception& err)
513{
514 LOG_WRN_P("Exception in %s (%s): %s", __func__, customTitle(instance).c_str(), err.what());
515}
516} // namespace tree
517//! @brief To apply tree-related instances that are mapped to choices.
518//! @param candidates - container for the candidate target choices
519void applyingTree(const std::vector<std::string>& candidates)
520{
521 constexpr auto category = Category::tree;
522 const auto& spec = categoryOpts<category>();
523 if (spec.none())
524 {
525 return;
526 }
527 MACRO_ASSERT(spec.size() == candidates.size());
528
529 const std::string_view title = data_structure::tree::description();
530 APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN(title);
531
532 auto& pooling = configure::task::resourcePool();
533 auto* const allocatedJob = pooling.newEntry(args: spec.count());
534 const auto taskNamer = utility::currying::curry(curried: curriedTaskName(), args: categoryAlias<category>());
535 const auto addTask = [allocatedJob, &taskNamer](const std::string_view subTask, const TreeInstance instance)
536 { allocatedJob->enqueue(name: taskNamer(subTask), func&: tree::structure, args: instance); };
537 MACRO_DEFER(utility::common::wrapClosure([&]() { pooling.deleteEntry(allocatedJob); }));
538
539 std::cout << "\nInstances of the " << toString(cat: category) << " structure:" << std::endl;
540 for (const auto index :
541 std::views::iota(0U, spec.size()) | std::views::filter([&spec](const auto i) { return spec.test(position: i); }))
542 {
543 const auto& choice = candidates.at(n: index);
544 switch (utility::common::bkdrHash(str: choice.c_str()))
545 {
546 case abbrLitHash(instance: TreeInstance::binarySearch):
547 addTask(choice, TreeInstance::binarySearch);
548 break;
549 case abbrLitHash(instance: TreeInstance::adelsonVelskyLandis):
550 addTask(choice, TreeInstance::adelsonVelskyLandis);
551 break;
552 case abbrLitHash(instance: TreeInstance::splay):
553 addTask(choice, TreeInstance::splay);
554 break;
555 default:
556 throw std::runtime_error{"Unknown " + std::string{toString(cat: category)} + " choice: " + choice + '.'};
557 }
558 }
559
560 APP_DS_PRINT_TASK_TITLE_SCOPE_END(title);
561}
562} // namespace application::app_ds
563
564#undef APP_DS_PRINT_TASK_TITLE_SCOPE_BEGIN
565#undef APP_DS_PRINT_TASK_TITLE_SCOPE_END
566