21 using FlagValue = std::variant<int, float, double, std::string, bool, size_t>;
32 void Register(
const std::string& longName,
const T& defaultValue )
34 if (flags_.count(longName))
35 throw std::runtime_error(
"Flag already registered: " + longName);
37 flags_[longName] = defaultValue;
41 void Register(
const std::string& longName,
42 const T& defaultValue,
43 const std::vector<T>& options )
45 this->Register(longName, defaultValue);
47 std::vector<FlagValue> convertedOptions;
48 convertedOptions.reserve(options.size());
50 for (
const T& val : options)
51 convertedOptions.push_back(val);
53 options_[longName] = std::move(convertedOptions);
58 T Get (
const std::string& name )
const
60 auto it = flags_.find(name);
61 if (it == flags_.end())
62 throw std::runtime_error(
"Flag not found: " + name);
64 return std::get<T>(it->second);
69 std::vector<T> GetOptions(
const std::string& name )
const
71 auto it = options_.find(name);
72 if (it == options_.end())
73 throw std::runtime_error(
"Flag not found: " + name);
75 return _ExtractTypedVector<T>(it->second, name);
80 void Set (
const std::string& name,
const T& value )
82 auto it = flags_.find(name);
83 if (it == flags_.end())
84 throw std::runtime_error(
"Flag not found: " + name);
90 void Parse (
int argc,
char** argv )
92 for (
int i = 1; i < argc; ++i)
94 std::string arg = argv[i];
97 if (arg.size() >= 3 && arg.substr(0, 2) ==
"--")
99 std::string flag = arg.substr(2);
101 if (flags_.count(flag) == 0)
102 throw std::runtime_error(
"Error: Unknown flag '--" + flag +
"'");
105 if (i + 1 < argc && argv[i + 1][0] !=
'-')
110 if (!std::holds_alternative<bool>(flags_[flag]))
111 throw std::runtime_error(
"Error: Missing value for flag '--" +
116 Set(flag, ParseValue(flag, value));
121 throw std::runtime_error(
"Error: Invalid argument format '" + arg +
"'");
126 void Print ( std::ostream& out = std::cout )
128 out << std::string(50,
'-') <<
"\n"
130 << std::setw(25) <<
"Flag Name"
131 << std::setw(25) <<
"Flag Value" << std::endl
132 << std::string(50,
'-') <<
"\n";
134 for (
const auto &entry : flags_)
136 const auto &key = entry.first;
137 const auto &value = entry.second;
139 std::string value_str;
140 std::string type_str;
142 std::visit([&](
const auto &val)
144 std::ostringstream oss;
146 value_str = oss.str();
151 << std::setw(25) << key
152 << std::setw(25) << value_str
155 out << std::string(50,
'-') <<
"\n";
159 std::string Sanitize (
const std::string &input )
const
161 std::string output = input;
164 std::replace(output.begin(), output.end(),
'.',
'p');
167 for (
char &c : output)
168 if (!std::isalnum(
static_cast<unsigned char>(c)))
175 std::string GenName ( )
const
177 std::vector<std::string> keys;
178 for (
const auto &pair : flags_)
180 keys.push_back(pair.first);
182 std::sort(keys.begin(), keys.end());
184 std::ostringstream oss;
186 for (
const auto &key : keys)
188 const auto &value = flags_.at(key);
190 std::string value_str;
191 std::visit([&](
const auto &val)
193 std::ostringstream val_stream;
195 if constexpr (std::is_same_v<decltype(val),
bool>)
196 val_stream << (val ?
"true" :
"false");
200 value_str = val_stream.str();
203 oss << Sanitize(key) <<
"_" << Sanitize(value_str) <<
"-";
206 std::string result = oss.str();
208 result.erase(result.size() - 1);
214 std::string GenName(
const std::vector<std::string>& include_keys)
const
216 std::vector<std::string> keys;
217 for (
const auto &key : include_keys)
219 if (flags_.find(key) != flags_.end())
224 std::sort(keys.begin(), keys.end());
226 std::ostringstream oss;
228 for (
const auto &key : keys)
230 const auto &value = flags_.at(key);
232 std::string value_str;
233 std::visit([&](
const auto &val)
235 std::ostringstream val_stream;
237 if constexpr (std::is_same_v<decltype(val),
bool>)
238 val_stream << (val ?
"true" :
"false");
242 value_str = val_stream.str();
245 oss << Sanitize(key) <<
"_" << Sanitize(value_str) <<
"-";
248 std::string result = oss.str();
250 result.erase(result.size() - 1);
257 std::vector<T> _ExtractTypedVector(
const std::vector<FlagValue>& input,
258 const std::string& name)
const
260 std::vector<T> output;
261 for (
const auto& val : input)
263 if (!std::holds_alternative<T>(val))
264 throw std::runtime_error(
"Type mismatch in options for flag: " + name);
266 output.push_back(std::get<T>(val));
274 std::unordered_map<std::string, FlagValue> flags_;
276 std::unordered_map<std::string, std::vector<FlagValue>> options_;
279 FlagValue ParseValue(
const std::string& name,
const std::string& valueStr)
281 const auto& val = flags_.at(name);
282 if (std::holds_alternative<int>(val))
283 return std::stoi(valueStr);
284 if (std::holds_alternative<size_t>(val))
285 return static_cast<size_t>(std::stoi(valueStr));
286 if (std::holds_alternative<float>(val))
287 return std::stof(valueStr);
288 if (std::holds_alternative<double>(val))
289 return std::stod(valueStr);
290 if (std::holds_alternative<std::string>(val))
292 if (std::holds_alternative<bool>(val))
293 return valueStr ==
"true" || valueStr ==
"1";
294 throw std::runtime_error(
"Unsupported flag type for: " + name);