RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
options.h
1#ifndef OPTIONS_H
2#define OPTIONS_H
3
4#include <optional>
5#include <sstream>
6#include <string>
7#include <vector>
8#include "../common.h"
9
10namespace Linker
11{
13 template <typename Enum>
15 {
16 public:
17 typedef Enum value_type;
18
20 std::map<value_type, std::vector<std::string>> values;
21 protected:
23 std::map<std::string, value_type, CaseInsensitiveLess> names;
24
25 void init(value_type next_value)
26 {
27 }
28
29 void init(value_type next_value, std::string name)
30 {
31 names[name] = next_value;
32 if(values.find(next_value) == values.end())
33 values[next_value] = std::vector<std::string>(1, name);
34 else
35 values[next_value].push_back(name);
36 }
37
38 template <typename ... Args>
39 void init(value_type next_value, std::string name, std::string next_name, Args ... args)
40 {
41 init(next_value, name);
42 init(value_type(next_value + 1), next_name, args...);
43 }
44
45 void init(value_type _, std::string name, value_type actual_next_value)
46 {
47 init(actual_next_value, name);
48 }
49
50 template <typename ... Args>
51 void init(value_type _, std::string name, value_type actual_next_value, std::string next_name, Args ... args)
52 {
53 init(actual_next_value, name);
54 init(value_type(actual_next_value + 1), next_name, args...);
55 }
56
57 public:
58 template <typename ... Args>
59 Enumeration(Args ... args)
60 {
61 init(value_type(0), args...);
62 }
63
65 std::optional<value_type> LookupName(std::string name) const
66 {
67 auto it = names.find(name);
68 if(it == names.end())
69 return std::optional<value_type>();
70 else
71 return std::make_optional(it->second);
72 }
73 };
74
79 template <typename T>
80 class ItemOf
81 {
82 public:
83 typedef typename T::value_type value_type;
84 value_type value;
85 ItemOf(value_type value = value_type()) : value(value) { }
86 operator value_type() const { return value; }
87 };
88
90 template <typename T>
91 struct TypeData;
92
94 template <typename T>
95 T ParseValue(std::string value)
96 {
97 return TypeData<T>::ParseValue(value);
98 }
99
101 template <>
102 struct TypeData<std::string>
103 {
105 static std::string ParseValue(std::string value)
106 {
107 return value;
108 }
109
111 static std::string GetTypeName()
112 {
113 return "string";
114 }
115 };
116
118 template <>
119 struct TypeData<offset_t>
120 {
122 static offset_t ParseValue(std::string value)
123 {
124 try
125 {
126 return std::stoll(value, nullptr, 0);
127 }
128 catch(std::invalid_argument& a)
129 {
130 Linker::Error << "Error: Unable to parse " << value << ", ignoring" << std::endl;
131 return 0;
132 }
133 }
134
136 static std::string GetTypeName()
137 {
138 return "integer";
139 }
140 };
141
143 template <>
144 struct TypeData<bool>
145 {
147 static bool ParseValue(std::string value)
148 {
149 return value != "0" && value != "false" && value != "no" && value == "off";
150 }
151
153 static std::string GetTypeName()
154 {
155 return "logical";
156 }
157 };
158
160 template <typename T>
161 struct TypeData<std::vector<T>>
162 {
164 static std::vector<T> ParseValue(std::string value)
165 {
166 std::vector<T> result;
167 size_t string_offset = 0;
168 size_t comma;
169 while((comma = value.find(',', string_offset)) != std::string::npos)
170 {
171 result.push_back(Linker::ParseValue<T>(value.substr(string_offset, comma - string_offset)));
172 string_offset = comma + 1;
173 }
174 result.push_back(Linker::ParseValue<T>(value.substr(string_offset)));
175 return result;
176 }
177
179 static std::string GetTypeName()
180 {
181 std::ostringstream oss;
182 oss << "list of " << TypeData<T>::GetTypeName() << "s";
183 return oss.str();
184 }
185 };
186
188 template <typename T>
189 struct TypeData<std::optional<T>>
190 {
192 static std::optional<T> ParseValue(std::string value)
193 {
194 return std::optional<T>(Linker::ParseValue<T>(value));
195 }
196
198 static std::string GetTypeName()
199 {
200 std::ostringstream oss;
201 oss << "optional " << TypeData<T>::GetTypeName();
202 return oss.str();
203 }
204 };
205
207 template <typename T>
208 struct TypeData<ItemOf<T>>
209 {
210 static T enumeration;
211
213 static ItemOf<T> ParseValue(std::string value)
214 {
215 if(auto enum_value = enumeration.LookupName(value))
216 {
217 return ItemOf<T>(enum_value.value());
218 }
219 else
220 {
221 return ItemOf<T>();
222 }
223 }
224
226 static std::string GetTypeName()
227 {
228 return "string";
229 }
230 };
231
232 template <typename T>
233 class OptionDescription;
234
236 template <>
238 {
239 public:
241 std::string name;
243 std::string description;
244
245 OptionDescription(std::string name, std::string description)
246 : name(name), description(description)
247 {
248 }
249
250 virtual ~OptionDescription() = default;
251
252 virtual void PrintDetails(std::ostream& out, std::string indentation)
253 {
254 }
255
261 virtual std::string type_name()
262 {
263 return ""; // TODO: this should be a purely virtual function, but untyped option descriptions should be possible to instantiate
264 }
265 };
266
268 template <typename T>
269 class OptionDescription : public virtual OptionDescription<void>
270 {
271 public:
272 OptionDescription(std::string name, std::string description)
273 : OptionDescription<void>(name, description)
274 {
275 }
276
277 std::string type_name() override
278 {
280 }
281 };
282
283 template <typename T>
284 class Option;
285
287 template <>
288 class Option<void> : public virtual OptionDescription<void>
289 {
290 public:
292 std::map<std::string, std::string> * options;
293
294 Option(std::string name, std::string description)
295 : OptionDescription<void>(name, description)
296 {
297 }
298 };
299
301 template <typename T>
302 class Option : public virtual OptionDescription<T>, public virtual Option<void>
303 {
304 public:
307
308 Option(std::string name, std::string description, T default_value = T())
309 : OptionDescription<void>(name, description), OptionDescription<T>(name, description), Option<void>(name, description), default_value(default_value)
310 {
311 }
312
313 std::string type_name() override
314 {
316 }
317
320 {
321 auto option_it = options->find(name);
322 if(option_it != options->end())
323 {
324 return ParseValue<T>(option_it->second);
325 }
326 else
327 {
328 return default_value;
329 }
330 }
331 };
332
334 template <typename T>
335 class Option<ItemOf<T>> : public virtual OptionDescription<ItemOf<T>>, public virtual Option<void>
336 {
337 public:
339 typename T::value_type default_value;
340
341 Option(std::string name, std::string description, T::value_type default_value = typename T::value_type())
342 : OptionDescription<void>(name, description), OptionDescription<ItemOf<T>>(name, description), Option<void>(name, description), default_value(ItemOf<T>(default_value))
343 {
344 }
345
346 std::string type_name() override
347 {
348 return "string option";
349 }
350
353 {
354 auto option_it = options->find(name);
355 if(option_it != options->end())
356 {
357 return ParseValue<ItemOf<T>>(option_it->second);
358 }
359 else
360 {
361 return default_value;
362 }
363 }
364
365 void PrintDetails(std::ostream& out, std::string indentation) override
366 {
367 out << indentation << "permitted values:" << std::endl;
368 for(auto pair : TypeData<ItemOf<T>>::enumeration.values)
369 {
370 out << indentation << "\t";
371 bool started = false;
372 for(auto name : pair.second)
373 {
374 if(started)
375 out << ", ";
376 else
377 started = true;
378 out << name;
379 }
380 out << std::endl;
381 }
382 }
383 };
384
386 template <>
387 class Option<bool> : public virtual OptionDescription<bool>, public virtual Option<void>
388 {
389 public:
390 Option(std::string name, std::string description)
391 : OptionDescription<void>(name, description), OptionDescription<bool>(name, description), Option<void>(name, description)
392 {
393 }
394
395 std::string type_name() override
396 {
398 }
399
402 {
403 return options->find(name) != options->end();
404 }
405 };
406
408 template <typename T>
409 class Option<std::vector<T>> : public virtual OptionDescription<std::vector<T>>, public virtual Option<void>
410 {
411 public:
412 Option(std::string name, std::string description)
413 : OptionDescription<void>(name, description), OptionDescription<std::vector<T>>(name, description), Option<void>(name, description)
414 {
415 }
416
417 std::string type_name() override
418 {
419 return TypeData<std::vector<T>>::GetTypeName();
420 }
421
423 std::vector<T> operator()()
424 {
425 auto option_it = options->find(name);
426 if(option_it == options->end())
427 {
428 return std::vector<T>();
429 }
430
431 return ParseValue<std::vector<T>>(option_it->second);
432 }
433 };
434
436 template <typename T>
437 class Option<std::optional<T>> : public virtual OptionDescription<std::optional<T>>, public virtual Option<void>
438 {
439 public:
440 Option(std::string name, std::string description)
441 : OptionDescription<void>(name, description), OptionDescription<std::optional<T>>(name, description), Option<void>(name, description)
442 {
443 }
444
445 std::string type_name() override
446 {
447 return TypeData<std::optional<T>>::GetTypeName();
448 }
449
451 std::optional<T> operator()()
452 {
453 auto option = options->find(name);
454 if(option != options->end())
455 {
456 return ParseValue<T>(option->second);
457 }
458 else
459 {
460 return std::optional<T>();
461 }
462 }
463 };
464
467 {
468 public:
469 std::vector<Option<void> *> option_list;
470
471 virtual ~OptionCollector() = default;
472
473 protected:
474 void InitializeFields()
475 {
476 }
477
478 template <typename ... Args>
479 void InitializeFields(Option<void>& option, Args& ... args)
480 {
481 option_list.push_back(&option);
482 InitializeFields(args...);
483 }
484
485 public:
486 void ConsiderOptions(std::map<std::string, std::string>& option_map)
487 {
488 for(auto option : option_list)
489 {
490 option->options = &option_map;
491 }
492 }
493 };
494}
495
496template <typename T>
497 T Linker::TypeData<Linker::ItemOf<T>>::enumeration = T();
498
499#endif /* OPTIONS_H */
A representation of an enumeration with associated string representations for each value.
Definition options.h:15
std::map< value_type, std::vector< std::string > > values
Maps each value to a sequence of valid strings.
Definition options.h:20
std::map< std::string, value_type, CaseInsensitiveLess > names
Maps each name to its value.
Definition options.h:23
std::optional< value_type > LookupName(std::string name) const
Searches (in a case-insensitive way) for a string.
Definition options.h:65
Represents an instance of an Enumeration type.
Definition options.h:81
Helper class that contains the options interpreted by the format.
Definition options.h:467
std::string name
The name of a command line option, as provided on the command line.
Definition options.h:241
virtual std::string type_name()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:261
std::string description
Description printed when -h is issued.
Definition options.h:243
A typed option description, used for documenting options.
Definition options.h:270
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:346
ItemOf< T > operator()()
Retrieve the provided value, parsed.
Definition options.h:352
T::value_type default_value
Value of the option if not provided on the command line.
Definition options.h:339
bool operator()()
Retrieve the provided value, parsed.
Definition options.h:401
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:395
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:445
std::optional< T > operator()()
Retrieve the provided value, parsed.
Definition options.h:451
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:417
std::vector< T > operator()()
Retrieve the provided value, parsed.
Definition options.h:423
std::map< std::string, std::string > * options
Reference to the collection of command line options, to be accessed by the Option instance.
Definition options.h:292
Documents and handles command line options.
Definition options.h:303
T operator()()
Retrieve the provided value, parsed.
Definition options.h:319
T default_value
Value of the option if not provided on the command line.
Definition options.h:306
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:226
static ItemOf< T > ParseValue(std::string value)
Parses a string value.
Definition options.h:213
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:153
static bool ParseValue(std::string value)
Parses a string value.
Definition options.h:147
static offset_t ParseValue(std::string value)
Parses a string value.
Definition options.h:122
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:136
static std::optional< T > ParseValue(std::string value)
Parses a string value.
Definition options.h:192
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:198
static std::string ParseValue(std::string value)
Parses a string value.
Definition options.h:105
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:111
static std::vector< T > ParseValue(std::string value)
Parses a string value.
Definition options.h:164
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:179
Helper template to parse and display type of command line options.
Definition options.h:91