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::string> descriptions;
21
23 std::map<value_type, std::vector<std::string>> values;
24 protected:
26 std::map<std::string, value_type, CaseInsensitiveLess> names;
27
28 void init(value_type next_value)
29 {
30 }
31
32 void init(value_type next_value, std::string name)
33 {
34 names[name] = next_value;
35 if(values.find(next_value) == values.end())
36 values[next_value] = std::vector<std::string>(1, name);
37 else
38 values[next_value].push_back(name);
39 }
40
41 template <typename ... Args>
42 void init(value_type next_value, std::string name, std::string next_name, Args ... args)
43 {
44 init(next_value, name);
45 init(value_type(next_value + 1), next_name, args...);
46 }
47
48 void init(value_type _, std::string name, value_type actual_next_value)
49 {
50 init(actual_next_value, name);
51 }
52
53 template <typename ... Args>
54 void init(value_type _, std::string name, value_type actual_next_value, std::string next_name, Args ... args)
55 {
56 init(actual_next_value, name);
57 init(value_type(actual_next_value + 1), next_name, args...);
58 }
59
60 public:
61 template <typename ... Args>
62 Enumeration(Args ... args)
63 {
64 init(value_type(0), args...);
65 }
66
68 std::optional<value_type> LookupName(std::string name) const
69 {
70 auto it = names.find(name);
71 if(it == names.end())
72 return std::optional<value_type>();
73 else
74 return std::make_optional(it->second);
75 }
76 };
77
82 template <typename T>
83 class ItemOf
84 {
85 public:
86 typedef typename T::value_type value_type;
87 value_type value;
88 ItemOf(value_type value = value_type()) : value(value) { }
89 operator value_type() const { return value; }
90 };
91
93 template <typename T>
94 struct TypeData;
95
97 template <typename T>
98 T ParseValue(std::string value)
99 {
100 return TypeData<T>::ParseValue(value);
101 }
102
104 template <>
105 struct TypeData<std::string>
106 {
108 static std::string ParseValue(std::string value)
109 {
110 return value;
111 }
112
114 static std::string GetTypeName()
115 {
116 return "string";
117 }
118 };
119
121 template <>
122 struct TypeData<offset_t>
123 {
125 static offset_t ParseValue(std::string value)
126 {
127 try
128 {
129 return std::stoll(value, nullptr, 0);
130 }
131 catch(std::invalid_argument& a)
132 {
133 Linker::Error << "Error: Unable to parse " << value << ", ignoring" << std::endl;
134 return 0;
135 }
136 }
137
139 static std::string GetTypeName()
140 {
141 return "integer";
142 }
143 };
144
146 template <>
147 struct TypeData<bool>
148 {
150 static bool ParseValue(std::string value)
151 {
152 return value != "0" && value != "false" && value != "no" && value == "off";
153 }
154
156 static std::string GetTypeName()
157 {
158 return "logical";
159 }
160 };
161
163 template <typename T>
164 struct TypeData<std::vector<T>>
165 {
167 static std::vector<T> ParseValue(std::string value)
168 {
169 std::vector<T> result;
170 size_t string_offset = 0;
171 size_t comma;
172 while((comma = value.find(',', string_offset)) != std::string::npos)
173 {
174 result.push_back(Linker::ParseValue<T>(value.substr(string_offset, comma - string_offset)));
175 string_offset = comma + 1;
176 }
177 result.push_back(Linker::ParseValue<T>(value.substr(string_offset)));
178 return result;
179 }
180
182 static std::string GetTypeName()
183 {
184 std::ostringstream oss;
185 oss << "list of " << TypeData<T>::GetTypeName() << "s";
186 return oss.str();
187 }
188 };
189
191 template <typename T>
192 struct TypeData<std::optional<T>>
193 {
195 static std::optional<T> ParseValue(std::string value)
196 {
197 return std::optional<T>(Linker::ParseValue<T>(value));
198 }
199
201 static std::string GetTypeName()
202 {
203 std::ostringstream oss;
204 oss << "optional " << TypeData<T>::GetTypeName();
205 return oss.str();
206 }
207 };
208
210 template <typename T>
211 struct TypeData<ItemOf<T>>
212 {
213 static T enumeration;
214
216 static ItemOf<T> ParseValue(std::string value)
217 {
218 if(auto enum_value = enumeration.LookupName(value))
219 {
220 return ItemOf<T>(enum_value.value());
221 }
222 else
223 {
224 return ItemOf<T>();
225 }
226 }
227
229 static std::string GetTypeName()
230 {
231 return "string";
232 }
233 };
234
235 template <typename T>
236 class OptionDescription;
237
239 template <>
241 {
242 public:
244 std::string name;
246 std::string description;
247
248 OptionDescription(std::string name, std::string description)
249 : name(name), description(description)
250 {
251 }
252
253 virtual ~OptionDescription() = default;
254
255 virtual void PrintDetails(std::ostream& out, std::string indentation)
256 {
257 }
258
264 virtual std::string type_name()
265 {
266 return ""; // TODO: this should be a purely virtual function, but untyped option descriptions should be possible to instantiate
267 }
268 };
269
271 template <typename T>
272 class OptionDescription : public virtual OptionDescription<void>
273 {
274 public:
275 OptionDescription(std::string name, std::string description)
276 : OptionDescription<void>(name, description)
277 {
278 }
279
280 std::string type_name() override
281 {
283 }
284 };
285
286 template <typename T>
287 class Option;
288
290 template <>
291 class Option<void> : public virtual OptionDescription<void>
292 {
293 public:
295 std::map<std::string, std::string> * options;
296
297 Option(std::string name, std::string description)
298 : OptionDescription<void>(name, description)
299 {
300 }
301 };
302
304 template <typename T>
305 class Option : public virtual OptionDescription<T>, public virtual Option<void>
306 {
307 public:
310
311 Option(std::string name, std::string description, T default_value = T())
312 : OptionDescription<void>(name, description), OptionDescription<T>(name, description), Option<void>(name, description), default_value(default_value)
313 {
314 }
315
316 std::string type_name() override
317 {
319 }
320
323 {
324 auto option_it = options->find(name);
325 if(option_it != options->end())
326 {
327 return ParseValue<T>(option_it->second);
328 }
329 else
330 {
331 return default_value;
332 }
333 }
334 };
335
337 template <typename T>
338 class Option<ItemOf<T>> : public virtual OptionDescription<ItemOf<T>>, public virtual Option<void>
339 {
340 public:
342 typename T::value_type default_value;
343
344 Option(std::string name, std::string description, T::value_type default_value = typename T::value_type())
345 : OptionDescription<void>(name, description), OptionDescription<ItemOf<T>>(name, description), Option<void>(name, description), default_value(ItemOf<T>(default_value))
346 {
347 }
348
349 std::string type_name() override
350 {
351 return "string option";
352 }
353
356 {
357 auto option_it = options->find(name);
358 if(option_it != options->end())
359 {
360 return ParseValue<ItemOf<T>>(option_it->second);
361 }
362 else
363 {
364 return default_value;
365 }
366 }
367
368 void PrintDetails(std::ostream& out, std::string indentation) override
369 {
370 out << indentation << "permitted values:" << std::endl;
371 for(auto pair : TypeData<ItemOf<T>>::enumeration.values)
372 {
373 out << indentation << "\t";
374 bool started = false;
375 for(auto name : pair.second)
376 {
377 if(started)
378 out << ", ";
379 else
380 started = true;
381 out << name;
382 }
383 out << std::endl;
384 if(TypeData<ItemOf<T>>::enumeration.descriptions.find(pair.first) != TypeData<ItemOf<T>>::enumeration.descriptions.end())
385 {
386 out << indentation << "\t\t" << TypeData<ItemOf<T>>::enumeration.descriptions[pair.first] << std::endl;
387 }
388 }
389 }
390 };
391
393 template <>
394 class Option<bool> : public virtual OptionDescription<bool>, public virtual Option<void>
395 {
396 public:
397 Option(std::string name, std::string description)
398 : OptionDescription<void>(name, description), OptionDescription<bool>(name, description), Option<void>(name, description)
399 {
400 }
401
402 std::string type_name() override
403 {
405 }
406
409 {
410 return options->find(name) != options->end();
411 }
412 };
413
415 template <typename T>
416 class Option<std::vector<T>> : public virtual OptionDescription<std::vector<T>>, public virtual Option<void>
417 {
418 public:
419 Option(std::string name, std::string description)
420 : OptionDescription<void>(name, description), OptionDescription<std::vector<T>>(name, description), Option<void>(name, description)
421 {
422 }
423
424 std::string type_name() override
425 {
426 return TypeData<std::vector<T>>::GetTypeName();
427 }
428
430 std::vector<T> operator()()
431 {
432 auto option_it = options->find(name);
433 if(option_it == options->end())
434 {
435 return std::vector<T>();
436 }
437
438 return ParseValue<std::vector<T>>(option_it->second);
439 }
440 };
441
443 template <typename T>
444 class Option<std::optional<T>> : public virtual OptionDescription<std::optional<T>>, public virtual Option<void>
445 {
446 public:
447 Option(std::string name, std::string description)
448 : OptionDescription<void>(name, description), OptionDescription<std::optional<T>>(name, description), Option<void>(name, description)
449 {
450 }
451
452 std::string type_name() override
453 {
454 return TypeData<std::optional<T>>::GetTypeName();
455 }
456
458 std::optional<T> operator()()
459 {
460 auto option = options->find(name);
461 if(option != options->end())
462 {
463 return ParseValue<T>(option->second);
464 }
465 else
466 {
467 return std::optional<T>();
468 }
469 }
470 };
471
474 {
475 public:
476 std::vector<Option<void> *> option_list;
477
478 virtual ~OptionCollector() = default;
479
480 protected:
481 void InitializeFields()
482 {
483 }
484
485 template <typename ... Args>
486 void InitializeFields(Option<void>& option, Args& ... args)
487 {
488 option_list.push_back(&option);
489 InitializeFields(args...);
490 }
491
492 public:
493 void ConsiderOptions(std::map<std::string, std::string>& option_map)
494 {
495 for(auto option : option_list)
496 {
497 option->options = &option_map;
498 }
499 }
500 };
501}
502
503template <typename T>
504 T Linker::TypeData<Linker::ItemOf<T>>::enumeration = T();
505
506#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:23
std::map< std::string, value_type, CaseInsensitiveLess > names
Maps each name to its value.
Definition options.h:26
std::map< value_type, std::string > descriptions
An empty dictionary that explains the value types in detail.
Definition options.h:20
std::optional< value_type > LookupName(std::string name) const
Searches (in a case-insensitive way) for a string.
Definition options.h:68
Represents an instance of an Enumeration type.
Definition options.h:84
Helper class that contains the options interpreted by the format.
Definition options.h:474
std::string name
The name of a command line option, as provided on the command line.
Definition options.h:244
virtual std::string type_name()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:264
std::string description
Description printed when -h is issued.
Definition options.h:246
A typed option description, used for documenting options.
Definition options.h:273
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:349
ItemOf< T > operator()()
Retrieve the provided value, parsed.
Definition options.h:355
T::value_type default_value
Value of the option if not provided on the command line.
Definition options.h:342
bool operator()()
Retrieve the provided value, parsed.
Definition options.h:408
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:402
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:452
std::optional< T > operator()()
Retrieve the provided value, parsed.
Definition options.h:458
std::string type_name() override
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:424
std::vector< T > operator()()
Retrieve the provided value, parsed.
Definition options.h:430
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:295
Documents and handles command line options.
Definition options.h:306
T operator()()
Retrieve the provided value, parsed.
Definition options.h:322
T default_value
Value of the option if not provided on the command line.
Definition options.h:309
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:229
static ItemOf< T > ParseValue(std::string value)
Parses a string value.
Definition options.h:216
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:156
static bool ParseValue(std::string value)
Parses a string value.
Definition options.h:150
static offset_t ParseValue(std::string value)
Parses a string value.
Definition options.h:125
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:139
static std::optional< T > ParseValue(std::string value)
Parses a string value.
Definition options.h:195
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:201
static std::string ParseValue(std::string value)
Parses a string value.
Definition options.h:108
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:114
static std::vector< T > ParseValue(std::string value)
Parses a string value.
Definition options.h:167
static std::string GetTypeName()
Returns a textual representation of the type, to be displayed to the user.
Definition options.h:182
Helper template to parse and display type of command line options.
Definition options.h:94