Maze Builder Docs 7.5.6
Loading...
Searching...
No Matches
create.h
Go to the documentation of this file.
1#ifndef CREATE_H
2#define CREATE_H
3
4#include <future>
5#include <mutex>
6#include <sstream>
7#include <string>
8#include <vector>
9
11#include <MazeBuilder/grid.h>
14#include <MazeBuilder/maze_factory.h>
21
24namespace mazes
25{
27 namespace detail
28 {
29 // Internal implementation - not intended for direct use
30 static std::string create_single(const configurator &config)
31 {
32 auto grid_creator = [](const configurator &config) -> std::unique_ptr<grid_interface>
33 {
34 return std::make_unique<grid>(config.rows(), config.columns(), config.levels());
35 };
36
37 auto maze_creator = [grid_creator](const configurator &config) -> std::unique_ptr<maze_interface>
38 {
39 static constexpr auto GRID_CREATION_ID{"g1"};
40
41 grid_factory gf{};
42
43 if (!gf.is_registered(GRID_CREATION_ID))
44 {
45
46 if (!gf.register_creator(GRID_CREATION_ID, grid_creator))
47 {
48
49 return nullptr;
50 }
51 }
52
53 if (auto igrid = gf.create(GRID_CREATION_ID, std::cref(config)); igrid.has_value())
54 {
55 static randomizer rng{};
56
57 rng.seed(config.seed());
58
59 if (auto algo_runner = configurator::make_algo_from_config(std::cref(config)); algo_runner.has_value())
60 {
61
62 auto &&igridimpl = igrid.value();
63
64 if (auto success = algo_runner.value()->run(igridimpl.get(), std::ref(rng)))
65 {
66 static stringify _stringifier;
67
68 _stringifier.run(igridimpl.get(), std::ref(rng));
69
70 return std::make_unique<maze_str>(igridimpl->operations().get_str());
71 }
72 }
73 }
74
75 return nullptr;
76 };
77
78 std::string s{};
79
80 auto duration = progress<>::duration([&config, &s, maze_creator]() -> bool
81 {
82 static constexpr auto MAZE_CREATION_ID{"m1"};
83
84 maze_factory mf{};
85
86 if (!mf.is_registered(MAZE_CREATION_ID))
87 {
88 if(!mf.register_creator(MAZE_CREATION_ID, maze_creator))
89 {
90 return false;
91 }
92 }
93
94 if (auto maze_optional = mf.create(MAZE_CREATION_ID, std::cref(config)); maze_optional.has_value())
95 {
96 s = maze_optional.value()->maze();
97 }
98
99 return !s.empty(); });
100
101 return s;
102 }
103
104 // Smart concurrency execution based on hardware capabilities
105 template <typename... Configs>
106 static std::vector<std::string> create_async(const Configs &...configs)
107 {
108 static_assert(sizeof...(configs) > 1, "Need multiple configs for concurrent execution");
109
110 const unsigned int hardware_threads = std::thread::hardware_concurrency();
111 const size_t num_configs = sizeof...(configs);
112
113 std::vector<std::string> results;
114 results.reserve(num_configs);
115
116 if (hardware_threads > 1 && num_configs >= 2)
117 {
118 // Use async execution for multi-core systems
119 std::vector<std::future<std::string>> futures;
120 futures.reserve(num_configs);
121
122 // Launch async tasks for each configuration
123 auto launch_async = [](const configurator &config)
124 {
125 return std::async(std::launch::async, [config]()
126 { return create_single(config); });
127 };
128
129 (futures.push_back(launch_async(configs)), ...);
130
131 // Collect results
132 for (auto &future : futures)
133 {
134 results.push_back(future.get());
135 }
136 }
137 else
138 {
139 // Fall back to serial execution for single-core or small workloads
140 (results.push_back(create_single(configs)), ...);
141 }
142
143 return results;
144 }
145 } // namespace detail
146
147 // Public API: Create maze from single configurator
148 template <typename Config>
149 static inline std::string create(const Config &config)
150 {
151 // Handle both direct configurator and reference_wrapper
152 using DecayedConfig = std::decay_t<Config>;
153
154 static_assert(
155 std::is_same_v<DecayedConfig, configurator> ||
156 std::is_same_v<DecayedConfig, std::reference_wrapper<configurator>> ||
157 std::is_same_v<DecayedConfig, std::reference_wrapper<const configurator>>,
158 "Parameter must be a configurator or reference to configurator");
159
160 // Handle reference wrapper by getting the actual configurator
161 if constexpr (std::is_same_v<DecayedConfig, std::reference_wrapper<configurator>> ||
162 std::is_same_v<DecayedConfig, std::reference_wrapper<const configurator>>)
163 {
164
165 return detail::create_single(config.get());
166 }
167 else
168 {
169
170 return detail::create_single(config);
171 }
172 }
173
174 // Public API: Create multiple mazes from multiple configurators
175 template <typename... Configs>
176 static inline std::vector<std::string> create(const Configs &...configs)
177 {
178 static_assert(sizeof...(configs) > 1, "Use single parameter version for one configurator");
179
180 // Handle both direct configurators and reference wrappers
181 static_assert(
182 ((std::is_same_v<std::decay_t<Configs>, configurator> ||
183 std::is_same_v<std::decay_t<Configs>, std::reference_wrapper<configurator>> ||
184 std::is_same_v<std::decay_t<Configs>, std::reference_wrapper<const configurator>>) &&
185 ...),
186 "All parameters must be configurator objects or references to configurators");
187
188 // Process each configurator and unwrap reference wrappers if needed
189 auto unwrap_config = [](const auto &cfg) -> const configurator &
190 {
191 using ConfigType = std::decay_t<decltype(cfg)>;
192 if constexpr (std::is_same_v<ConfigType, std::reference_wrapper<configurator>> ||
193 std::is_same_v<ConfigType, std::reference_wrapper<const configurator>>)
194 {
195 return cfg.get();
196 }
197 else
198 {
199 return cfg;
200 }
201 };
202
203 // Use smart concurrency execution
204 return detail::create_async(unwrap_config(configs)...);
205 }
206
207} // namespace mazes
208
209#endif // CREATE_H
static std::optional< std::unique_ptr< algo_interface > > make_algo_from_config(const configurator &config)
Determine the maze generation algorithm from the configuration.
Definition configurator.h:243
static Duration duration(F &&f, Args &&...args)
Definition progress.h:34
Namespace for the maze builder.
Definition algo_interface.h:6