Unravel Engine C++ Reference
Loading...
Searching...
No Matches
parser.h
Go to the documentation of this file.
1#pragma once
2#include <cstdint>
3#include <functional>
4#include <iostream>
5#include <memory>
6#include <sstream>
7#include <stdexcept>
8#include <string>
9#include <vector>
10
11namespace cmd_line
12{
13namespace detail
14{
15auto get_internal_id() -> std::uint64_t;
16
17template<typename T>
18inline auto get_id() -> std::uint64_t
19{
20 static std::uint64_t id = get_internal_id();
21 return id;
22}
23} // namespace detail
24
26template<typename T, int num_base = 0>
28{
29public:
31 numeric_base() : value(0), base(num_base)
32 {
33 }
34
37 numeric_base(T val) : value(val), base(num_base)
38 {
39 }
40
41 operator T() const
42 {
43 return this->value;
44 }
45 operator T*()
46 {
47 return this->value;
48 }
49
51 unsigned int base;
52};
53
55{
56 const std::vector<std::string>& arguments;
57 std::ostream& output;
58 std::ostream& error;
59};
60
61class parser
62{
63private:
64 class cmd_base
65 {
66 public:
67 explicit cmd_base(const std::string& name,
68 const std::string& alternative,
69 const std::string& description,
70 bool required,
71 bool dominant,
72 bool is_variadic);
73
74 virtual ~cmd_base();
75
76 std::string name;
77 std::string command;
78 std::string alternative;
79 std::string description;
80 bool required;
81 bool handled;
82 std::vector<std::string> arguments;
83 bool const dominant;
84 bool const variadic;
85
86 virtual auto print_value() const -> std::string = 0;
87 virtual auto parse(std::ostream& output, std::ostream& error) -> bool = 0;
88
89 auto is(const std::string& given) const -> bool;
90 };
91
92 template<typename T>
93 struct argument_count_checker
94 {
95 static constexpr bool variadic = false;
96 };
97
98 template<typename T>
99 struct argument_count_checker<cmd_line::numeric_base<T>>
100 {
101 static constexpr bool variadic = false;
102 };
103
104 template<typename T>
105 struct argument_count_checker<std::vector<T>>
106 {
107 static constexpr bool variadic = true;
108 };
109
110 template<typename T>
111 class cmd_function final : public cmd_base
112 {
113 public:
114 explicit cmd_function(const std::string& name,
115 const std::string& alternative,
116 const std::string& description,
117 bool required,
118 bool dominant)
119 : cmd_base(name, alternative, description, required, dominant, argument_count_checker<T>::variadic)
120 {
121 }
122
123 auto parse(std::ostream& output, std::ostream& error) -> bool override
124 {
125 try
126 {
127 callback_args args{arguments, output, error};
128 value = callback(args);
129 return true;
130 }
131 catch(...)
132 {
133 return false;
134 }
135 }
136
137 auto print_value() const -> std::string override
138 {
139 return "";
140 }
141
142 std::function<T(callback_args&)> callback;
143 T value;
144 };
145
146 template<typename T>
147 class cmd_argument final : public cmd_base
148 {
149 public:
150 explicit cmd_argument(const std::string& name,
151 const std::string& alternative,
152 const std::string& description,
153 bool required,
154 bool dominant)
155 : cmd_base(name, alternative, description, required, dominant, argument_count_checker<T>::variadic)
156 {
157 }
158
159 auto parse(std::ostream& /*output*/, std::ostream& /*error*/) -> bool override
160 {
161 try
162 {
163 value = parser::parse(arguments, value);
164 return true;
165 }
166 catch(...)
167 {
168 return false;
169 }
170 }
171
172 auto print_value() const -> std::string override
173 {
174 return stringify(value);
175 }
176
177 T value;
178 };
179
180 static auto parse(const std::vector<std::string>& elements, const int& /*unused*/, int numberBase = 0) -> int;
181
182 static auto parse(const std::vector<std::string>& elements, const bool& defval) -> bool;
183
184 static auto parse(const std::vector<std::string>& elements, const double& /*unused*/) -> double;
185
186 static auto parse(const std::vector<std::string>& elements, const float& /*unused*/) -> float;
187
188 static auto parse(const std::vector<std::string>& elements, const long double& /*unused*/) -> long double;
189
190 static auto parse(const std::vector<std::string>& elements, const unsigned int& /*unused*/, int numberBase = 0)
191 -> unsigned int;
192
193 static auto parse(const std::vector<std::string>& elements, const unsigned long& /*unused*/, int numberBase = 0)
194 -> unsigned long;
195
196 static auto parse(const std::vector<std::string>& elements, const long& /*unused*/) -> long;
197
198 static auto parse(const std::vector<std::string>& elements, const std::string& /*unused*/) -> std::string;
199
200 template<class T>
201 static auto parse(const std::vector<std::string>& elements, const std::vector<T>& /*unused*/) -> std::vector<T>
202 {
203 const T defval = T();
204 std::vector<T> values{};
205 std::vector<std::string> buffer(1);
206
207 for(const auto& element : elements)
208 {
209 buffer[0] = element;
210 values.push_back(parse(buffer, defval));
211 }
212
213 return values;
214 }
215
216 template<typename T>
217 static auto parse(const std::vector<std::string>& elements, const numeric_base<T>& wrapper) -> T
218 {
219 return parse(elements, wrapper.value, 0);
220 }
221
228 template<typename T, int base>
229 static auto parse(const std::vector<std::string>& elements, const numeric_base<T, base>& wrapper) -> T
230 {
231 return parse(elements, wrapper.value, wrapper.base);
232 }
233
234 template<class T>
235 static auto stringify(const T& value) -> std::string
236 {
237 return std::to_string(value);
238 }
239
240 template<class T, int base>
241 static auto stringify(const numeric_base<T, base>& wrapper) -> std::string
242 {
243 return std::to_string(wrapper.value);
244 }
245
246 template<class T>
247 static auto stringify(const std::vector<T>& values) -> std::string
248 {
249 std::stringstream ss{};
250 ss << "[ ";
251
252 for(const auto& value : values)
253 {
254 ss << stringify(value) << " ";
255 }
256
257 ss << "]";
258 return ss.str();
259 }
260
261 static auto stringify(const std::string& str) -> std::string;
262
263public:
264 explicit parser(int argc, const char** argv);
265
266 explicit parser(int argc, char** argv);
267
268
269 parser(const parser&) = delete;
270
271 parser(parser&&) = delete;
272
273 parser& operator=(const parser&) = delete;
274
275 parser& operator=(parser&&) = delete;
276
277 auto has_help() const -> bool;
278
279 void enable_help();
280
281 void disable_help();
282
283 void reset();
284
285 template<typename T>
286 void set_default(bool is_required, const std::string& description = "")
287 {
288 auto command = std::make_unique<cmd_argument<T>>("", "", description, is_required, false);
289 commands_.emplace_back(detail::get_id<cmd_argument<T>>(), std::move(command));
290 }
291
292 template<typename T>
293 void set_required(const std::string& name,
294 const std::string& alternative,
295 const std::string& description = "",
296 bool dominant = false)
297 {
298 auto command = std::make_unique<cmd_argument<T>>(name, alternative, description, true, dominant);
299 commands_.emplace_back(detail::get_id<cmd_argument<T>>(), std::move(command));
300 }
301
302 template<typename T>
303 void set_optional(const std::string& name,
304 const std::string& alternative,
305 T defaultValue,
306 const std::string& description = "",
307 bool dominant = false)
308 {
309 auto command = std::make_unique<cmd_argument<T>>(name, alternative, description, false, dominant);
310 command->value = defaultValue;
311 commands_.emplace_back(detail::get_id<cmd_argument<T>>(), std::move(command));
312 }
313
314 template<typename T>
315 void set_callback(const std::string& name,
316 const std::string& alternative,
317 std::function<T(callback_args&)> callback,
318 const std::string& description = "",
319 bool dominant = false)
320 {
321 auto command = std::make_unique<cmd_function<T>>(name, alternative, description, false, dominant);
322 command->callback = callback;
323 commands_.emplace_back(detail::get_id<cmd_function<T>>(), std::move(command));
324 }
325
327
328 auto run() -> bool;
329
330 auto run(std::ostream& output) -> bool;
331
332 auto run(std::ostream& output, std::ostream& error) -> bool;
333
334 template<typename T>
335 auto get(const std::string& name) const -> T
336 {
337 const std::string alternative_name = "--" + name;
338 for(const auto& command_pair : commands_)
339 {
340 const auto command_type_id = command_pair.first;
341 const auto& command = command_pair.second;
342 if(command->name == name || command->alternative == alternative_name)
343 {
344 const auto requested_id = detail::get_id<cmd_argument<T>>();
345 if(command_type_id != requested_id)
346 {
347 throw std::runtime_error("Invalid usage of the parameter " + name + " detected.");
348 }
349 else
350 {
351 auto cmd = static_cast<cmd_argument<T>*>(command.get());
352 if(cmd)
353 {
354 return cmd->value;
355 }
356 }
357 }
358 }
359
360 throw std::runtime_error("The parameter " + name + " could not be found.");
361 }
362
363 template<typename T>
364 auto try_get(const std::string& name, T& result) const -> bool
365 {
366 try
367 {
368 result = get<T>(name);
369 return true;
370 }
371 catch(const std::exception&)
372 {
373 return false;
374 }
375 }
376
377 template<typename T>
378 auto get_if(const std::string& name, std::function<T(T)> callback) const -> T
379 {
380 auto value = get<T>(name);
381 return callback(value);
382 }
383
384 auto requirements() const -> int;
385
386 auto commands() const -> int;
387
388 auto app_name() const -> const std::string&;
389
390 auto usage() const -> std::string;
391
392protected:
393 auto find(const std::string& name) -> cmd_base*;
394
395 auto find_default() -> cmd_base*;
396
397 void print_help(std::stringstream& ss) const;
398
399 auto howto_required(const std::unique_ptr<cmd_base>& command) const -> std::string;
400
401 auto howto_use(const std::unique_ptr<cmd_base>& command) const -> std::string;
402
403 auto no_default() const -> std::string;
404
405private:
406 const std::string appname_;
407 std::vector<std::string> arguments_;
408 std::vector<std::pair<std::uint64_t, std::unique_ptr<cmd_base>>> commands_;
409};
410} // namespace cmd_line
Class used to wrap integer types to specify desired numerical base for specific argument parsing.
Definition parser.h:28
numeric_base()
This constructor required for correct AgrumentCountChecker initialization.
Definition parser.h:31
unsigned int base
Definition parser.h:51
void set_optional(const std::string &name, const std::string &alternative, T defaultValue, const std::string &description="", bool dominant=false)
Definition parser.h:303
auto howto_required(const std::unique_ptr< cmd_base > &command) const -> std::string
Definition parser.cpp:354
auto has_help() const -> bool
Definition parser.cpp:151
auto get_if(const std::string &name, std::function< T(T)> callback) const -> T
Definition parser.h:378
void disable_help()
Definition parser.cpp:180
auto app_name() const -> const std::string &
Definition parser.cpp:311
void enable_help()
Definition parser.cpp:165
auto find_default() -> cmd_base *
Definition parser.cpp:381
void set_default(bool is_required, const std::string &description="")
Definition parser.h:286
auto usage() const -> std::string
Definition parser.cpp:316
auto run() -> bool
Definition parser.cpp:206
void run_and_exit_if_error()
Definition parser.cpp:198
void set_required(const std::string &name, const std::string &alternative, const std::string &description="", bool dominant=false)
Definition parser.h:293
void print_help(std::stringstream &ss) const
Definition parser.cpp:346
auto try_get(const std::string &name, T &result) const -> bool
Definition parser.h:364
void set_callback(const std::string &name, const std::string &alternative, std::function< T(callback_args &)> callback, const std::string &description="", bool dominant=false)
Definition parser.h:315
auto no_default() const -> std::string
Definition parser.cpp:372
auto howto_use(const std::unique_ptr< cmd_base > &command) const -> std::string
Definition parser.cpp:363
parser(const parser &)=delete
auto get(const std::string &name) const -> T
Definition parser.h:335
parser(int argc, const char **argv)
Definition parser.cpp:133
auto requirements() const -> int
Definition parser.cpp:290
auto commands() const -> int
Definition parser.cpp:306
auto find(const std::string &name) -> cmd_base *
Definition parser.cpp:395
parser & operator=(parser &&)=delete
parser & operator=(const parser &)=delete
parser(parser &&)=delete
std::string name
Definition hub.cpp:27
auto get_id() -> std::uint64_t
Definition parser.h:18
auto get_internal_id() -> std::uint64_t
Definition parser.cpp:6
std::ostream & output
Definition parser.h:57
const std::vector< std::string > & arguments
Definition parser.h:56
std::ostream & error
Definition parser.h:58