yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
flag.h
Go to the documentation of this file.
1#ifndef YAZE_UTIL_FLAG_H_
2#define YAZE_UTIL_FLAG_H_
3
4#include <memory>
5#include <sstream>
6#include <string>
7#include <unordered_map>
8#include <vector>
9
10namespace yaze {
11namespace util {
12
13namespace detail {
14[[noreturn]] void FlagParseFatal(const std::string& message);
15}
16
17// Base interface for all flags.
18class IFlag {
19 public:
20 virtual ~IFlag() = default;
21
22 // Returns the full name (e.g. "--count") used for this flag.
23 virtual const std::string& name() const = 0;
24
25 // Returns help text describing how to use this flag.
26 virtual const std::string& help() const = 0;
27
28 // Parses a string value into the underlying type.
29 virtual void ParseValue(const std::string& text) = 0;
30};
31
32template <typename T>
33class Flag : public IFlag {
34 public:
35 Flag(const std::string& name, const T& default_value,
36 const std::string& help_text)
37 : name_(name),
38 value_(default_value),
39 default_(default_value),
40 help_(help_text) {}
41
42 const std::string& name() const override { return name_; }
43 const std::string& help() const override { return help_; }
44
45 // Attempts to parse a string into type T using a stringstream.
46 void ParseValue(const std::string& text) override {
47 std::stringstream ss(text);
48 T parsed;
49 if (!(ss >> parsed)) {
50 detail::FlagParseFatal("Failed to parse flag: " + name_);
51 }
52 value_ = parsed;
53 }
54
55 // Set the value directly (used by specializations)
56 void SetValue(const T& val) { value_ = val; }
57
58 // Returns the current (parsed or default) value of the flag.
59 const T& Get() const { return value_; }
60
61 private:
62 std::string name_;
65 std::string help_;
66};
67
68// Specialization for bool to handle "true"/"false" strings
69template <>
70inline void Flag<bool>::ParseValue(const std::string& text) {
71 if (text == "true" || text == "1" || text == "yes" || text == "on") {
72 SetValue(true);
73 } else if (text == "false" || text == "0" || text == "no" || text == "off") {
74 SetValue(false);
75 } else {
77 "Failed to parse boolean flag: " + name() +
78 " (expected true/false/1/0/yes/no/on/off, got: " + text + ")");
79 }
80}
81
83 public:
84 // Registers a flag in the global registry.
85 // The return type is a pointer to the newly created flag.
86 template <typename T>
87 Flag<T>* RegisterFlag(const std::string& name, const T& default_value,
88 const std::string& help_text) {
89 auto flag = std::make_unique<Flag<T>>(name, default_value, help_text);
90 Flag<T>* raw_ptr =
91 flag.get(); // We keep a non-owning pointer to use later.
92 flags_[name] = std::move(flag);
93 return raw_ptr;
94 }
95
96 // Returns a shared interface pointer if found, otherwise nullptr.
97 IFlag* GetFlag(const std::string& name) const {
98 auto it = flags_.find(name);
99 if (it == flags_.end()) {
100 return nullptr;
101 }
102 return it->second.get();
103 }
104
105 // Returns all registered flags for iteration, help text, etc.
106 std::vector<IFlag*> AllFlags() const {
107 std::vector<IFlag*> result;
108 result.reserve(flags_.size());
109 for (auto const& kv : flags_) {
110 result.push_back(kv.second.get());
111 }
112 return result;
113 }
114
115 private:
116 std::unordered_map<std::string, std::unique_ptr<IFlag>> flags_;
117};
118
120 // Guaranteed to be initialized once per process.
121 static FlagRegistry* registry = new FlagRegistry();
122 return registry;
123}
124
125// Defines a global Flag<type>* FLAGS_<name> and registers it.
126#define DEFINE_FLAG(type, name, default_val, help_text) \
127 yaze::util::Flag<type>* FLAGS_##name = \
128 yaze::util::global_flag_registry()->RegisterFlag<type>( \
129 "--" #name, (default_val), (help_text))
130
131// Retrieves the current value of a declared flag.
132#define FLAG_VALUE(name) (FLAGS_##name->Get())
133
135 public:
136 explicit FlagParser(FlagRegistry* registry) : registry_(registry) {}
137
138 // Parses flags out of the given command line arguments.
139 void Parse(int argc, char** argv) {
140 std::vector<std::string> tokens;
141 for (int i = 0; i < argc; i++) {
142 tokens.push_back(argv[i]);
143 }
144 Parse(&tokens);
145 }
146
147 // Parses flags out of the given token list. Recognizes forms:
148 // --flag=value or --flag value
149 // Any token not recognized as a flag is left in `leftover`.
150 void Parse(std::vector<std::string>* tokens);
151
152 private:
154
155 // Checks if there is an '=' sign in the token, extracting flag name and
156 // value. e.g. "--count=42" -> flag_name = "--count", value_string = "42"
157 // returns true if '=' was found
158 bool ExtractFlagAndValue(const std::string& token, std::string* flag_name,
159 std::string* value_string);
160
161 // Mode flag '-'
162 bool ExtractFlag(const std::string& token, std::string* flag_name);
163};
164
165} // namespace util
166} // namespace yaze
167
168#endif // YAZE_UTIL_FLAG_H_
FlagRegistry * registry_
Definition flag.h:153
bool ExtractFlagAndValue(const std::string &token, std::string *flag_name, std::string *value_string)
Definition flag.cc:85
void Parse(int argc, char **argv)
Definition flag.h:139
FlagParser(FlagRegistry *registry)
Definition flag.h:136
bool ExtractFlag(const std::string &token, std::string *flag_name)
Definition flag.cc:97
Flag< T > * RegisterFlag(const std::string &name, const T &default_value, const std::string &help_text)
Definition flag.h:87
IFlag * GetFlag(const std::string &name) const
Definition flag.h:97
std::vector< IFlag * > AllFlags() const
Definition flag.h:106
std::unordered_map< std::string, std::unique_ptr< IFlag > > flags_
Definition flag.h:116
Flag(const std::string &name, const T &default_value, const std::string &help_text)
Definition flag.h:35
const std::string & name() const override
Definition flag.h:42
void ParseValue(const std::string &text) override
Definition flag.h:46
const std::string & help() const override
Definition flag.h:43
std::string help_
Definition flag.h:65
std::string name_
Definition flag.h:62
const T & Get() const
Definition flag.h:59
void SetValue(const T &val)
Definition flag.h:56
virtual void ParseValue(const std::string &text)=0
virtual ~IFlag()=default
virtual const std::string & name() const =0
virtual const std::string & help() const =0
void FlagParseFatal(const std::string &message)
Definition flag.cc:13
FlagRegistry * global_flag_registry()
Definition flag.h:119