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