123 struct OptionCompare {
124 using is_transparent = void;
125 bool operator()(
const std::string& lhs,
const std::string& rhs)
const noexcept
129 bool operator()(
const std::string& lhs, std::string_view rhs)
const noexcept
133 bool operator()(std::string_view lhs,
const std::string& rhs)
const noexcept
139 using Data = std::variant<Value, Help, NoOp, Switch>;
141 struct OptionData :
RefCount<OptionData, ThreadUnsafePolicy> {
142 template <
typename DataT>
143 OptionData(
char short_opt,
const std::string& long_opt, DataT
data, std::string description)
146 , description{std::move(description)}
149 this->short_opt.push_back(short_opt);
152 const std::string& opt()
const noexcept {
return long_opt.empty() ? short_opt : long_opt; }
154 std::string short_opt, long_opt;
156 std::string description;
159 using OptionDataPtr = boost::intrusive_ptr<OptionData>;
162 explicit Options(std::string description =
"");
164 template <
typename DataT>
166 std::string description =
"")
168 this->operator()(0, long_opt, std::forward<DataT>(option_data), std::move(description));
172 template <
typename DataT>
174 std::string description =
"")
176 auto opt_data = make_intrusive<OptionData>(short_opt, long_opt, std::forward<DataT>(
data),
177 std::move(description));
178 help_.push_back(opt_data);
180 const bool inserted = opts_.emplace(opt_data->short_opt, opt_data).second;
182 throw std::runtime_error{
"attempting to register duplicate option "
183 + opt_data->short_opt};
186 if (!long_opt.empty()) {
187 const bool inserted = opts_.emplace(long_opt, opt_data).second;
189 throw std::runtime_error{
"attempting to register duplicate option " + long_opt};
195 template <
typename DataT>
198 positional_.push_back(std::move(
data));
202 template <
typename DataT>
205 this->operator()(short_opt,
"", std::forward<DataT>(option_data), std::move(description));
209 bool operator[](
const std::string& long_opt)
const noexcept;
210 bool operator[](
char short_opt)
const noexcept;
211 void parse(
int argc,
const char*
const argv[]);
214 template <
typename StreamT>
218 std::string description_;
219 using HelpVec = std::vector<OptionDataPtr>;
221 using OptsMap = std::map<std::string, OptionDataPtr, OptionCompare>;
223 using DataVec = std::vector<Data>;
231 out <<
"Usage: " << options.description_ <<
"\nOptions:\n";
233 for (
const auto& opt : options.help_) {
234 unsigned max_width{15};
237 if (!opt->short_opt.empty()) {
239 out <<
'-' << opt->short_opt;
241 if (!opt->long_opt.empty()) {
242 if (!opt->short_opt.empty()) {
246 max_width -= 2 + opt->long_opt.size();
247 out <<
"--" << opt->long_opt;
249 out << std::format(
"{:{}}",
' ', max_width) << opt->description <<
'\n';