MLIR-AIE
cxxopts.hpp
Go to the documentation of this file.
1/*
2
3Copyright (c) 2014-2022 Jarryd Beck
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22
23*/
24
25// vim: ts=2:sw=2:expandtab
26
27#ifndef CXXOPTS_HPP_INCLUDED
28#define CXXOPTS_HPP_INCLUDED
29
30#include <algorithm>
31#include <cstdint>
32#include <cstdlib>
33#include <cstring>
34#include <exception>
35#include <initializer_list>
36#include <limits>
37#include <locale>
38#include <map>
39#include <memory>
40#include <sstream>
41#include <string>
42#include <unordered_map>
43#include <unordered_set>
44#include <utility>
45#include <vector>
46
47#ifdef CXXOPTS_NO_EXCEPTIONS
48#include <iostream>
49#endif
50
51#if defined(__GNUC__) && !defined(__clang__)
52#if (__GNUC__ * 10 + __GNUC_MINOR__) < 49
53#define CXXOPTS_NO_REGEX true
54#endif
55#endif
56#if defined(_MSC_VER) && !defined(__clang__)
57#define CXXOPTS_LINKONCE_CONST __declspec(selectany) extern
58#define CXXOPTS_LINKONCE __declspec(selectany) extern
59#else
60#define CXXOPTS_LINKONCE_CONST
61#define CXXOPTS_LINKONCE
62#endif
63
64#ifndef CXXOPTS_NO_REGEX
65#include <regex>
66#endif // CXXOPTS_NO_REGEX
67
68// Nonstandard before C++17, which is coincidentally what we also need for
69// <optional>
70#ifdef __has_include
71#if __has_include(<optional>)
72#include <optional>
73#ifdef __cpp_lib_optional
74#define CXXOPTS_HAS_OPTIONAL
75#endif
76#endif
77#if __has_include(<filesystem>)
78#include <filesystem>
79#ifdef __cpp_lib_filesystem
80#define CXXOPTS_HAS_FILESYSTEM
81#endif
82#endif
83#endif
84
85#define CXXOPTS_FALLTHROUGH
86#ifdef __has_cpp_attribute
87#if __has_cpp_attribute(fallthrough)
88#undef CXXOPTS_FALLTHROUGH
89#define CXXOPTS_FALLTHROUGH [[fallthrough]]
90#endif
91#endif
92
93#if __cplusplus >= 201603L
94#define CXXOPTS_NODISCARD [[nodiscard]]
95#else
96#define CXXOPTS_NODISCARD
97#endif
98
99#ifndef CXXOPTS_VECTOR_DELIMITER
100#define CXXOPTS_VECTOR_DELIMITER ','
101#endif
102
103#define CXXOPTS__VERSION_MAJOR 3
104#define CXXOPTS__VERSION_MINOR 2
105#define CXXOPTS__VERSION_PATCH 1
106
107#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6
108#define CXXOPTS_NULL_DEREF_IGNORE
109#endif
110
111#if defined(__GNUC__)
112#define DO_PRAGMA(x) _Pragma(#x)
113#define CXXOPTS_DIAGNOSTIC_PUSH DO_PRAGMA(GCC diagnostic push)
114#define CXXOPTS_DIAGNOSTIC_POP DO_PRAGMA(GCC diagnostic pop)
115#define CXXOPTS_IGNORE_WARNING(x) DO_PRAGMA(GCC diagnostic ignored x)
116#else
117// define other compilers here if needed
118#define CXXOPTS_DIAGNOSTIC_PUSH
119#define CXXOPTS_DIAGNOSTIC_POP
120#define CXXOPTS_IGNORE_WARNING(x)
121#endif
122
123#ifdef CXXOPTS_NO_RTTI
124#define CXXOPTS_RTTI_CAST static_cast
125#else
126#define CXXOPTS_RTTI_CAST dynamic_cast
127#endif
128
129namespace cxxopts {
130static constexpr struct {
131 uint8_t major, minor, patch;
134} // namespace cxxopts
135
136// when we ask cxxopts to use Unicode, help strings are processed using ICU,
137// which results in the correct lengths being computed for strings when they
138// are formatted for the help output
139// it is necessary to make sure that <unicode/unistr.h> can be found by the
140// compiler, and that icu-uc is linked in to the binary.
141
142#ifdef CXXOPTS_USE_UNICODE
143#include <unicode/unistr.h>
144
145namespace cxxopts {
146
147using String = icu::UnicodeString;
148
149inline String toLocalString(std::string s) {
150 return icu::UnicodeString::fromUTF8(std::move(s));
151}
152
153// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we
154// want to silence it: warning: base class 'class
155// std::enable_shared_from_this<cxxopts::Value>' has accessible non-virtual
156// destructor
158CXXOPTS_IGNORE_WARNING("-Wnon-virtual-dtor")
159// This will be ignored under other compilers like LLVM clang.
160class UnicodeStringIterator {
161public:
162 using iterator_category = std::forward_iterator_tag;
163 using value_type = int32_t;
164 using difference_type = std::ptrdiff_t;
165 using pointer = value_type *;
166 using reference = value_type &;
167
168 UnicodeStringIterator(const icu::UnicodeString *string, int32_t pos)
169 : s(string), i(pos) {}
170
171 value_type operator*() const { return s->char32At(i); }
172
173 bool operator==(const UnicodeStringIterator &rhs) const {
174 return s == rhs.s && i == rhs.i;
175 }
176
177 bool operator!=(const UnicodeStringIterator &rhs) const {
178 return !(*this == rhs);
179 }
180
181 UnicodeStringIterator &operator++() {
182 ++i;
183 return *this;
184 }
185
186 UnicodeStringIterator operator+(int32_t v) {
187 return UnicodeStringIterator(s, i + v);
188 }
189
190private:
191 const icu::UnicodeString *s;
192 int32_t i;
193};
195
196inline String &stringAppend(String &s, String a) {
197 return s.append(std::move(a));
198}
199
200inline String &stringAppend(String &s, std::size_t n, UChar32 c) {
201 for (std::size_t i = 0; i != n; ++i) {
202 s.append(c);
203 }
204
205 return s;
206}
207
208template <typename Iterator>
209String &stringAppend(String &s, Iterator begin, Iterator end) {
210 while (begin != end) {
211 s.append(*begin);
212 ++begin;
213 }
214
215 return s;
216}
217
218inline size_t stringLength(const String &s) {
219 return static_cast<size_t>(s.length());
220}
221
222inline std::string toUTF8String(const String &s) {
223 std::string result;
224 s.toUTF8String(result);
225
226 return result;
227}
228
229inline bool empty(const String &s) { return s.isEmpty(); }
230
231} // namespace cxxopts
232
233namespace std {
234
235inline cxxopts::UnicodeStringIterator begin(const icu::UnicodeString &s) {
236 return cxxopts::UnicodeStringIterator(&s, 0);
237}
238
239inline cxxopts::UnicodeStringIterator end(const icu::UnicodeString &s) {
240 return cxxopts::UnicodeStringIterator(&s, s.length());
241}
242
243} // namespace std
244
245// ifdef CXXOPTS_USE_UNICODE
246#else
247
248namespace cxxopts {
249
250using String = std::string;
251
252template <typename T>
254 return std::forward<T>(t);
255}
256
257inline std::size_t stringLength(const String &s) { return s.length(); }
258
259inline String &stringAppend(String &s, const String &a) { return s.append(a); }
260
261inline String &stringAppend(String &s, std::size_t n, char c) {
262 return s.append(n, c);
263}
264
265template <typename Iterator>
266String &stringAppend(String &s, Iterator begin, Iterator end) {
267 return s.append(begin, end);
268}
269
270template <typename T>
271std::string toUTF8String(T &&t) {
272 return std::forward<T>(t);
273}
274
275inline bool empty(const std::string &s) { return s.empty(); }
276
277} // namespace cxxopts
278
279// ifdef CXXOPTS_USE_UNICODE
280#endif
281
282namespace cxxopts {
283
284namespace {
285CXXOPTS_LINKONCE_CONST std::string LQUOTE("\'");
286CXXOPTS_LINKONCE_CONST std::string RQUOTE("\'");
287} // namespace
288
289// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we
290// want to silence it: warning: base class 'class
291// std::enable_shared_from_this<cxxopts::Value>' has accessible non-virtual
292// destructor This will be ignored under other compilers like LLVM clang.
294CXXOPTS_IGNORE_WARNING("-Wnon-virtual-dtor")
295
296// some older versions of GCC warn under this warning
297CXXOPTS_IGNORE_WARNING("-Weffc++")
298class Value : public std::enable_shared_from_this<Value> {
299public:
300 virtual ~Value() = default;
301
302 virtual std::shared_ptr<Value> clone() const = 0;
303
304 virtual void add(const std::string &text) const = 0;
305
306 virtual void parse(const std::string &text) const = 0;
307
308 virtual void parse() const = 0;
309
310 virtual bool has_default() const = 0;
311
312 virtual bool is_container() const = 0;
313
314 virtual bool has_implicit() const = 0;
315
316 virtual std::string get_default_value() const = 0;
317
318 virtual std::string get_implicit_value() const = 0;
319
320 virtual std::shared_ptr<Value> default_value(const std::string &value) = 0;
321
322 virtual std::shared_ptr<Value> implicit_value(const std::string &value) = 0;
323
324 virtual std::shared_ptr<Value> no_implicit_value() = 0;
325
326 virtual bool is_boolean() const = 0;
327};
328
330
331namespace exceptions {
332
333class exception : public std::exception {
334public:
335 explicit exception(std::string message) : m_message(std::move(message)) {}
336
338 const char *what() const noexcept override { return m_message.c_str(); }
339
340private:
341 std::string m_message;
342};
343
344class specification : public exception {
345public:
346 explicit specification(const std::string &message) : exception(message) {}
347};
348
349class parsing : public exception {
350public:
351 explicit parsing(const std::string &message) : exception(message) {}
352};
353
355public:
356 explicit option_already_exists(const std::string &option)
357 : specification("Option " + LQUOTE + option + RQUOTE +
358 " already exists") {}
359};
360
362public:
363 explicit invalid_option_format(const std::string &format)
364 : specification("Invalid option format " + LQUOTE + format + RQUOTE) {}
365};
366
368public:
369 explicit invalid_option_syntax(const std::string &text)
370 : parsing("Argument " + LQUOTE + text + RQUOTE +
371 " starts with a - but has incorrect syntax") {}
372};
373
374class no_such_option : public parsing {
375public:
376 explicit no_such_option(const std::string &option)
377 : parsing("Option " + LQUOTE + option + RQUOTE + " does not exist") {}
378};
379
380class missing_argument : public parsing {
381public:
382 explicit missing_argument(const std::string &option)
383 : parsing("Option " + LQUOTE + option + RQUOTE +
384 " is missing an argument") {}
385};
386
388public:
389 explicit option_requires_argument(const std::string &option)
390 : parsing("Option " + LQUOTE + option + RQUOTE +
391 " requires an argument") {}
392};
393
395public:
396 gratuitous_argument_for_option(const std::string &option,
397 const std::string &arg)
398 : parsing("Option " + LQUOTE + option + RQUOTE +
399 " does not take an argument, but argument " + LQUOTE + arg +
400 RQUOTE + " given") {}
401};
402
404public:
405 explicit requested_option_not_present(const std::string &option)
406 : parsing("Option " + LQUOTE + option + RQUOTE + " not present") {}
407};
408
410public:
411 explicit option_has_no_value(const std::string &option)
412 : exception(!option.empty()
413 ? ("Option " + LQUOTE + option + RQUOTE + " has no value")
414 : "Option has no value") {}
415};
416
418public:
419 explicit incorrect_argument_type(const std::string &arg)
420 : parsing("Argument " + LQUOTE + arg + RQUOTE + " failed to parse") {}
421};
422
423} // namespace exceptions
424
425template <typename T>
426void throw_or_mimic(const std::string &text) {
427 static_assert(std::is_base_of<std::exception, T>::value,
428 "throw_or_mimic only works on std::exception and "
429 "deriving classes");
430
431#ifndef CXXOPTS_NO_EXCEPTIONS
432 // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
433 throw T{text};
434#else
435 // Otherwise manually instantiate the exception, print what() to stderr,
436 // and exit
437 T exception{text};
438 std::cerr << exception.what() << std::endl;
439 std::exit(EXIT_FAILURE);
440#endif
441}
442
443using OptionNames = std::vector<std::string>;
444
445namespace values {
446
447namespace parser_tool {
448
450 std::string negative = "";
451 std::string base = "";
452 std::string value = "";
453};
454struct ArguDesc {
455 std::string arg_name = "";
456 bool grouping = false;
457 bool set_value = false;
458 std::string value = "";
459};
460
461#ifdef CXXOPTS_NO_REGEX
462inline IntegerDesc SplitInteger(const std::string &text) {
463 if (text.empty()) {
464 throw_or_mimic<exceptions::incorrect_argument_type>(text);
465 }
466 IntegerDesc desc;
467 const char *pdata = text.c_str();
468 if (*pdata == '-') {
469 pdata += 1;
470 desc.negative = "-";
471 }
472 if (strncmp(pdata, "0x", 2) == 0) {
473 pdata += 2;
474 desc.base = "0x";
475 }
476 if (*pdata != '\0') {
477 desc.value = std::string(pdata);
478 } else {
479 throw_or_mimic<exceptions::incorrect_argument_type>(text);
480 }
481 return desc;
482}
483
484inline bool IsTrueText(const std::string &text) {
485 const char *pdata = text.c_str();
486 if (*pdata == 't' || *pdata == 'T') {
487 pdata += 1;
488 if (strncmp(pdata, "rue\0", 4) == 0) {
489 return true;
490 }
491 } else if (strncmp(pdata, "1\0", 2) == 0) {
492 return true;
493 }
494 return false;
495}
496
497inline bool IsFalseText(const std::string &text) {
498 const char *pdata = text.c_str();
499 if (*pdata == 'f' || *pdata == 'F') {
500 pdata += 1;
501 if (strncmp(pdata, "alse\0", 5) == 0) {
502 return true;
503 }
504 } else if (strncmp(pdata, "0\0", 2) == 0) {
505 return true;
506 }
507 return false;
508}
509
510inline OptionNames split_option_names(const std::string &text) {
511 OptionNames split_names;
512
513 std::string::size_type token_start_pos = 0;
514 auto length = text.length();
515
516 if (length == 0) {
517 throw_or_mimic<exceptions::invalid_option_format>(text);
518 }
519
520 while (token_start_pos < length) {
521 const auto &npos = std::string::npos;
522 auto next_non_space_pos = text.find_first_not_of(' ', token_start_pos);
523 if (next_non_space_pos == npos) {
524 throw_or_mimic<exceptions::invalid_option_format>(text);
525 }
526 token_start_pos = next_non_space_pos;
527 auto next_delimiter_pos = text.find(',', token_start_pos);
528 if (next_delimiter_pos == token_start_pos) {
529 throw_or_mimic<exceptions::invalid_option_format>(text);
530 }
531 if (next_delimiter_pos == npos) {
532 next_delimiter_pos = length;
533 }
534 auto token_length = next_delimiter_pos - token_start_pos;
535 // validate the token itself matches the regex /([:alnum:][-_[:alnum:]]*/
536 {
537 const char *option_name_valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
538 "abcdefghijklmnopqrstuvwxyz"
539 "0123456789"
540 "_-.?";
541
542 if (!std::isalnum(text[token_start_pos], std::locale::classic()) ||
543 text.find_first_not_of(option_name_valid_chars, token_start_pos) <
544 next_delimiter_pos) {
545 throw_or_mimic<exceptions::invalid_option_format>(text);
546 }
547 }
548 split_names.emplace_back(text.substr(token_start_pos, token_length));
549 token_start_pos = next_delimiter_pos + 1;
550 }
551 return split_names;
552}
553
554inline ArguDesc ParseArgument(const char *arg, bool &matched) {
555 ArguDesc argu_desc;
556 const char *pdata = arg;
557 matched = false;
558 if (strncmp(pdata, "--", 2) == 0) {
559 pdata += 2;
560 if (isalnum(*pdata, std::locale::classic())) {
561 argu_desc.arg_name.push_back(*pdata);
562 pdata += 1;
563 while (isalnum(*pdata, std::locale::classic()) || *pdata == '-' ||
564 *pdata == '_') {
565 argu_desc.arg_name.push_back(*pdata);
566 pdata += 1;
567 }
568 if (argu_desc.arg_name.length() > 1) {
569 if (*pdata == '=') {
570 argu_desc.set_value = true;
571 pdata += 1;
572 if (*pdata != '\0') {
573 argu_desc.value = std::string(pdata);
574 }
575 matched = true;
576 } else if (*pdata == '\0') {
577 matched = true;
578 }
579 }
580 }
581 } else if (strncmp(pdata, "-", 1) == 0) {
582 pdata += 1;
583 argu_desc.grouping = true;
584 while (isalnum(*pdata, std::locale::classic())) {
585 argu_desc.arg_name.push_back(*pdata);
586 pdata += 1;
587 }
588 matched = !argu_desc.arg_name.empty() && *pdata == '\0';
589 }
590 return argu_desc;
591}
592
593#else // CXXOPTS_NO_REGEX
594
595namespace {
597const char *const integer_pattern = "(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)";
599const char *const truthy_pattern = "(t|T)(rue)?|1";
601const char *const falsy_pattern = "(f|F)(alse)?|0";
603const char *const option_pattern =
604 "--([[:alnum:]][-_[:alnum:]\\.]+)(=(.*))?|-([[:alnum:]].*)";
606const char *const option_specifier_pattern =
607 "([[:alnum:]][-_[:alnum:]\\.]*)(,[ ]*[[:alnum:]][-_[:alnum:]]*)*";
609const char *const option_specifier_separator_pattern = ", *";
610
611} // namespace
612
613inline IntegerDesc SplitInteger(const std::string &text) {
614 static const std::basic_regex<char> integer_matcher(integer_pattern);
615
616 std::smatch match;
617 std::regex_match(text, match, integer_matcher);
618
619 if (match.length() == 0) {
620 throw_or_mimic<exceptions::incorrect_argument_type>(text);
621 }
622
623 IntegerDesc desc;
624 desc.negative = match[1];
625 desc.base = match[2];
626 desc.value = match[3];
627
628 if (match.length(4) > 0) {
629 desc.base = match[5];
630 desc.value = "0";
631 return desc;
632 }
633
634 return desc;
635}
636
637inline bool IsTrueText(const std::string &text) {
638 static const std::basic_regex<char> truthy_matcher(truthy_pattern);
639 std::smatch result;
640 std::regex_match(text, result, truthy_matcher);
641 return !result.empty();
642}
643
644inline bool IsFalseText(const std::string &text) {
645 static const std::basic_regex<char> falsy_matcher(falsy_pattern);
646 std::smatch result;
647 std::regex_match(text, result, falsy_matcher);
648 return !result.empty();
649}
650
651// Gets the option names specified via a single, comma-separated string,
652// and returns the separate, space-discarded, non-empty names
653// (without considering which or how many are single-character)
654inline OptionNames split_option_names(const std::string &text) {
655 static const std::basic_regex<char> option_specifier_matcher(
656 option_specifier_pattern);
657 if (!std::regex_match(text.c_str(), option_specifier_matcher)) {
658 throw_or_mimic<exceptions::invalid_option_format>(text);
659 }
660
661 OptionNames split_names;
662
663 static const std::basic_regex<char> option_specifier_separator_matcher(
664 option_specifier_separator_pattern);
665 constexpr int use_non_matches{-1};
666 auto token_iterator = std::sregex_token_iterator(
667 text.begin(), text.end(), option_specifier_separator_matcher,
668 use_non_matches);
669 std::copy(token_iterator, std::sregex_token_iterator(),
670 std::back_inserter(split_names));
671 return split_names;
672}
673
674inline ArguDesc ParseArgument(const char *arg, bool &matched) {
675 static const std::basic_regex<char> option_matcher(option_pattern);
676 std::match_results<const char *> result;
677 std::regex_match(arg, result, option_matcher);
678 matched = !result.empty();
679
680 ArguDesc argu_desc;
681 if (matched) {
682 argu_desc.arg_name = result[1].str();
683 argu_desc.set_value = result[2].length() > 0;
684 argu_desc.value = result[3].str();
685 if (result[4].length() > 0) {
686 argu_desc.grouping = true;
687 argu_desc.arg_name = result[4].str();
688 }
689 }
690
691 return argu_desc;
692}
693
694#endif // CXXOPTS_NO_REGEX
695#undef CXXOPTS_NO_REGEX
696} // namespace parser_tool
697
698namespace detail {
699
700template <typename T, bool B>
702
703template <typename T>
704struct SignedCheck<T, true> {
705 template <typename U>
706 void operator()(bool negative, U u, const std::string &text) {
707 if (negative) {
708 if (u > static_cast<U>((std::numeric_limits<T>::min)())) {
709 throw_or_mimic<exceptions::incorrect_argument_type>(text);
710 }
711 } else {
712 if (u > static_cast<U>((std::numeric_limits<T>::max)())) {
713 throw_or_mimic<exceptions::incorrect_argument_type>(text);
714 }
715 }
716 }
717};
718
719template <typename T>
720struct SignedCheck<T, false> {
721 template <typename U>
722 void operator()(bool, U, const std::string &) const {}
723};
724
725template <typename T, typename U>
726void check_signed_range(bool negative, U value, const std::string &text) {
728}
729
730} // namespace detail
731
732template <typename R, typename T>
733void checked_negate(R &r, T &&t, const std::string &, std::true_type) {
734 // if we got to here, then `t` is a positive number that fits into
735 // `R`. So to avoid MSVC C4146, we first cast it to `R`.
736 // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
737 r = static_cast<R>(-static_cast<R>(t - 1) - 1);
738}
739
740template <typename R, typename T>
741void checked_negate(R &, T &&, const std::string &text, std::false_type) {
742 throw_or_mimic<exceptions::incorrect_argument_type>(text);
743}
744
745template <typename T>
746void integer_parser(const std::string &text, T &value) {
748
749 using US = typename std::make_unsigned<T>::type;
750 constexpr bool is_signed = std::numeric_limits<T>::is_signed;
751
752 const bool negative = int_desc.negative.length() > 0;
753 const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
754 const std::string &value_match = int_desc.value;
755
756 US result = 0;
757
758 for (char ch : value_match) {
759 US digit = 0;
760
761 if (ch >= '0' && ch <= '9') {
762 digit = static_cast<US>(ch - '0');
763 } else if (base == 16 && ch >= 'a' && ch <= 'f') {
764 digit = static_cast<US>(ch - 'a' + 10);
765 } else if (base == 16 && ch >= 'A' && ch <= 'F') {
766 digit = static_cast<US>(ch - 'A' + 10);
767 } else {
768 throw_or_mimic<exceptions::incorrect_argument_type>(text);
769 }
770
771 US limit = 0;
772 if (negative) {
773 limit = static_cast<US>(
774 std::abs(static_cast<intmax_t>((std::numeric_limits<T>::min)())));
775 } else {
776 limit = (std::numeric_limits<T>::max)();
777 }
778
779 if (base != 0 && result > limit / base) {
780 throw_or_mimic<exceptions::incorrect_argument_type>(text);
781 }
782 if (result * base > limit - digit) {
783 throw_or_mimic<exceptions::incorrect_argument_type>(text);
784 }
785
786 result = static_cast<US>(result * base + digit);
787 }
788
789 detail::check_signed_range<T>(negative, result, text);
790
791 if (negative) {
792 checked_negate<T>(value, result, text,
793 std::integral_constant<bool, is_signed>());
794 } else {
795 value = static_cast<T>(result);
796 }
797}
798
799template <typename T>
800void stringstream_parser(const std::string &text, T &value) {
801 std::stringstream in(text);
802 in >> value;
803 if (!in) {
804 throw_or_mimic<exceptions::incorrect_argument_type>(text);
805 }
806}
807
808template <typename T,
809 typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
810void parse_value(const std::string &text, T &value) {
811 integer_parser(text, value);
812}
813
814inline void parse_value(const std::string &text, bool &value) {
815 if (parser_tool::IsTrueText(text)) {
816 value = true;
817 return;
818 }
819
820 if (parser_tool::IsFalseText(text)) {
821 value = false;
822 return;
823 }
824
825 throw_or_mimic<exceptions::incorrect_argument_type>(text);
826}
827
828inline void parse_value(const std::string &text, std::string &value) {
829 value = text;
830}
831
832// The fallback parser. It uses the stringstream parser to parse all types
833// that have not been overloaded explicitly. It has to be placed in the
834// source code before all other more specialized templates.
835template <typename T, typename std::enable_if<!std::is_integral<T>::value>::type
836 * = nullptr>
837void parse_value(const std::string &text, T &value) {
839}
840
841#ifdef CXXOPTS_HAS_OPTIONAL
842template <typename T>
843void parse_value(const std::string &text, std::optional<T> &value) {
844 T result;
845 parse_value(text, result);
846 value = std::move(result);
847}
848#endif
849
850#ifdef CXXOPTS_HAS_FILESYSTEM
851inline void parse_value(const std::string &text, std::filesystem::path &value) {
852 value.assign(text);
853}
854#endif
855
856inline void parse_value(const std::string &text, char &c) {
857 if (text.length() != 1) {
858 throw_or_mimic<exceptions::incorrect_argument_type>(text);
859 }
860
861 c = text[0];
862}
863
864template <typename T>
865void parse_value(const std::string &text, std::vector<T> &value) {
866 if (text.empty()) {
867 T v;
868 parse_value(text, v);
869 value.emplace_back(std::move(v));
870 return;
871 }
872 std::stringstream in(text);
873 std::string token;
874 while (!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
875 T v;
876 parse_value(token, v);
877 value.emplace_back(std::move(v));
878 }
879}
880
881template <typename T>
882void add_value(const std::string &text, T &value) {
883 parse_value(text, value);
884}
885
886template <typename T>
887void add_value(const std::string &text, std::vector<T> &value) {
888 T v;
889 add_value(text, v);
890 value.emplace_back(std::move(v));
891}
892
893template <typename T>
895 static constexpr bool value = false;
896};
897
898template <typename T>
899struct type_is_container<std::vector<T>> {
900 static constexpr bool value = true;
901};
902
903template <typename T>
904class abstract_value : public Value {
905 using Self = abstract_value<T>;
906
907public:
908 abstract_value() : m_result(std::make_shared<T>()), m_store(m_result.get()) {}
909
910 explicit abstract_value(T *t) : m_store(t) {}
911
912 ~abstract_value() override = default;
913
915
917 if (rhs.m_result) {
918 m_result = std::make_shared<T>();
919 m_store = m_result.get();
920 } else {
921 m_store = rhs.m_store;
922 }
923
924 m_default = rhs.m_default;
928 }
929
930 void add(const std::string &text) const override {
931 add_value(text, *m_store);
932 }
933
934 void parse(const std::string &text) const override {
935 parse_value(text, *m_store);
936 }
937
938 bool is_container() const override { return type_is_container<T>::value; }
939
940 void parse() const override { parse_value(m_default_value, *m_store); }
941
942 bool has_default() const override { return m_default; }
943
944 bool has_implicit() const override { return m_implicit; }
945
946 std::shared_ptr<Value> default_value(const std::string &value) override {
947 m_default = true;
949 return shared_from_this();
950 }
951
952 std::shared_ptr<Value> implicit_value(const std::string &value) override {
953 m_implicit = true;
955 return shared_from_this();
956 }
957
958 std::shared_ptr<Value> no_implicit_value() override {
959 m_implicit = false;
960 return shared_from_this();
961 }
962
963 std::string get_default_value() const override { return m_default_value; }
964
965 std::string get_implicit_value() const override { return m_implicit_value; }
966
967 bool is_boolean() const override { return std::is_same<T, bool>::value; }
968
969 const T &get() const {
970 if (m_store == nullptr) {
971 return *m_result;
972 }
973 return *m_store;
974 }
975
976protected:
977 std::shared_ptr<T> m_result{};
979
980 bool m_default = false;
981 bool m_implicit = false;
982
983 std::string m_default_value{};
984 std::string m_implicit_value{};
985};
986
987template <typename T>
989public:
991
993 std::shared_ptr<Value> clone() const override {
994 return std::make_shared<standard_value<T>>(*this);
995 }
996};
997
998template <>
999class standard_value<bool> : public abstract_value<bool> {
1000public:
1001 ~standard_value() override = default;
1002
1003 standard_value() { set_default_and_implicit(); }
1004
1005 explicit standard_value(bool *b) : abstract_value(b) {
1006 m_implicit = true;
1007 m_implicit_value = "true";
1008 }
1009
1010 std::shared_ptr<Value> clone() const override {
1011 return std::make_shared<standard_value<bool>>(*this);
1012 }
1013
1014private:
1015 void set_default_and_implicit() {
1016 m_default = true;
1017 m_default_value = "false";
1018 m_implicit = true;
1019 m_implicit_value = "true";
1020 }
1021};
1022
1023} // namespace values
1024
1025template <typename T>
1026std::shared_ptr<Value> value() {
1027 return std::make_shared<values::standard_value<T>>();
1028}
1029
1030template <typename T>
1031std::shared_ptr<Value> value(T &t) {
1032 return std::make_shared<values::standard_value<T>>(&t);
1033}
1034
1035class OptionAdder;
1036
1038inline const std::string &first_or_empty(const OptionNames &long_names) {
1039 static const std::string empty{""};
1040 return long_names.empty() ? empty : long_names.front();
1041}
1042
1044public:
1045 OptionDetails(std::string short_, OptionNames long_, String desc,
1046 std::shared_ptr<const Value> val)
1047 : m_short(std::move(short_)), m_long(std::move(long_)),
1048 m_desc(std::move(desc)), m_value(std::move(val)), m_count(0) {
1049 m_hash = std::hash<std::string>{}(first_long_name() + m_short);
1050 }
1051
1053 : m_desc(rhs.m_desc), m_value(rhs.m_value->clone()),
1054 m_count(rhs.m_count) {}
1055
1057
1059 const String &description() const { return m_desc; }
1060
1062 const Value &value() const { return *m_value; }
1063
1065 std::shared_ptr<Value> make_storage() const { return m_value->clone(); }
1066
1068 const std::string &short_name() const { return m_short; }
1069
1071 const std::string &first_long_name() const { return first_or_empty(m_long); }
1072
1074 const std::string &essential_name() const {
1075 return m_long.empty() ? m_short : m_long.front();
1076 }
1077
1079 const OptionNames &long_names() const { return m_long; }
1080
1081 std::size_t hash() const { return m_hash; }
1082
1083private:
1084 std::string m_short{};
1085 OptionNames m_long{};
1086 String m_desc{};
1087 std::shared_ptr<const Value> m_value{};
1088 int m_count;
1089
1090 std::size_t m_hash{};
1091};
1092
1105
1107 std::string name{};
1108 std::string description{};
1109 std::vector<HelpOptionDetails> options{};
1110};
1111
1113public:
1114 void add(const std::shared_ptr<const OptionDetails> &details,
1115 const std::string &text) {
1116 ensure_value(details);
1117 ++m_count;
1118 m_value->add(text);
1119 m_long_names = &details->long_names();
1120 }
1121
1122 void parse(const std::shared_ptr<const OptionDetails> &details,
1123 const std::string &text) {
1124 ensure_value(details);
1125 ++m_count;
1126 m_value->parse(text);
1127 m_long_names = &details->long_names();
1128 }
1129
1130 void parse_default(const std::shared_ptr<const OptionDetails> &details) {
1131 ensure_value(details);
1132 m_default = true;
1133 m_long_names = &details->long_names();
1134 m_value->parse();
1135 }
1136
1137 void parse_no_value(const std::shared_ptr<const OptionDetails> &details) {
1138 m_long_names = &details->long_names();
1139 }
1140
1141#if defined(CXXOPTS_NULL_DEREF_IGNORE)
1143 CXXOPTS_IGNORE_WARNING("-Wnull-dereference")
1144#endif
1145
1147 std::size_t count() const noexcept { return m_count; }
1148
1149#if defined(CXXOPTS_NULL_DEREF_IGNORE)
1151#endif
1152
1153 // TODO: maybe default options should count towards the number of arguments
1155 bool has_default() const noexcept { return m_default; }
1156
1157 template <typename T>
1158 const T &as() const {
1159 if (m_value == nullptr) {
1160 throw_or_mimic<exceptions::option_has_no_value>(
1161 m_long_names == nullptr ? "" : first_or_empty(*m_long_names));
1162 }
1163
1164 return CXXOPTS_RTTI_CAST<const values::standard_value<T> &>(*m_value).get();
1165 }
1166
1167#ifdef CXXOPTS_HAS_OPTIONAL
1168 template <typename T>
1169 std::optional<T> as_optional() const {
1170 if (m_value == nullptr) {
1171 return std::nullopt;
1172 }
1173 return as<T>();
1174 }
1175#endif
1176
1177private:
1178 void ensure_value(const std::shared_ptr<const OptionDetails> &details) {
1179 if (m_value == nullptr) {
1180 m_value = details->make_storage();
1181 }
1182 }
1183
1184 const OptionNames *m_long_names = nullptr;
1185 // Holding this pointer is safe, since OptionValue's only exist in key-value
1186 // pairs, where the key has the string we point to.
1187 std::shared_ptr<Value> m_value{};
1188 std::size_t m_count = 0;
1189 bool m_default = false;
1190};
1191
1193public:
1194 KeyValue(std::string key_, std::string value_) noexcept
1195 : m_key(std::move(key_)), m_value(std::move(value_)) {}
1196
1198 const std::string &key() const { return m_key; }
1199
1201 const std::string &value() const { return m_value; }
1202
1203 template <typename T>
1204 T as() const {
1205 T result;
1206 values::parse_value(m_value, result);
1207 return result;
1208 }
1209
1210private:
1211 std::string m_key;
1212 std::string m_value;
1213};
1214
1215using ParsedHashMap = std::unordered_map<std::size_t, OptionValue>;
1216using NameHashMap = std::unordered_map<std::string, std::size_t>;
1217
1219public:
1220 class Iterator {
1221 public:
1222 using iterator_category = std::forward_iterator_tag;
1224 using difference_type = void;
1225 using pointer = const KeyValue *;
1226 using reference = const KeyValue &;
1227
1228 Iterator() = default;
1229 Iterator(const Iterator &) = default;
1230
1231 // GCC complains about m_iter not being initialised in the member
1232 // initializer list
1234 CXXOPTS_IGNORE_WARNING("-Weffc++")
1235 Iterator(const ParseResult *pr, bool end = false) : m_pr(pr) {
1236 if (end) {
1237 m_sequential = false;
1238 m_iter = m_pr->m_defaults.end();
1239 } else {
1240 m_sequential = true;
1241 m_iter = m_pr->m_sequential.begin();
1242
1243 if (m_iter == m_pr->m_sequential.end()) {
1244 m_sequential = false;
1245 m_iter = m_pr->m_defaults.begin();
1246 }
1247 }
1248 }
1250
1252 ++m_iter;
1253 if (m_sequential && m_iter == m_pr->m_sequential.end()) {
1254 m_sequential = false;
1255 m_iter = m_pr->m_defaults.begin();
1256 return *this;
1257 }
1258 return *this;
1259 }
1260
1262 Iterator retval = *this;
1263 ++(*this);
1264 return retval;
1265 }
1266
1267 bool operator==(const Iterator &other) const {
1268 return (m_sequential == other.m_sequential) && (m_iter == other.m_iter);
1269 }
1270
1271 bool operator!=(const Iterator &other) const { return !(*this == other); }
1272
1273 const KeyValue &operator*() { return *m_iter; }
1274
1275 const KeyValue *operator->() { return m_iter.operator->(); }
1276
1277 private:
1278 const ParseResult *m_pr;
1279 std::vector<KeyValue>::const_iterator m_iter;
1280 bool m_sequential = true;
1281 };
1282
1283 ParseResult() = default;
1284 ParseResult(const ParseResult &) = default;
1285
1287 std::vector<KeyValue> sequential,
1288 std::vector<KeyValue> default_opts,
1289 std::vector<std::string> &&unmatched_args)
1290 : m_keys(std::move(keys)), m_values(std::move(values)),
1291 m_sequential(std::move(sequential)),
1292 m_defaults(std::move(default_opts)),
1293 m_unmatched(std::move(unmatched_args)) {}
1294
1296 ParseResult &operator=(const ParseResult &) = default;
1297
1298 Iterator begin() const { return Iterator(this); }
1299
1300 Iterator end() const { return Iterator(this, true); }
1301
1302 std::size_t count(const std::string &o) const {
1303 auto iter = m_keys.find(o);
1304 if (iter == m_keys.end()) {
1305 return 0;
1306 }
1307
1308 auto viter = m_values.find(iter->second);
1309
1310 if (viter == m_values.end()) {
1311 return 0;
1312 }
1313
1314 return viter->second.count();
1315 }
1316
1317 bool contains(const std::string &o) const {
1318 return static_cast<bool>(count(o));
1319 }
1320
1321 const OptionValue &operator[](const std::string &option) const {
1322 auto iter = m_keys.find(option);
1323
1324 if (iter == m_keys.end()) {
1325 throw_or_mimic<exceptions::requested_option_not_present>(option);
1326 }
1327
1328 auto viter = m_values.find(iter->second);
1329
1330 if (viter == m_values.end()) {
1331 throw_or_mimic<exceptions::requested_option_not_present>(option);
1332 }
1333
1334 return viter->second;
1335 }
1336
1337#ifdef CXXOPTS_HAS_OPTIONAL
1338 template <typename T>
1339 std::optional<T> as_optional(const std::string &option) const {
1340 auto iter = m_keys.find(option);
1341 if (iter != m_keys.end()) {
1342 auto viter = m_values.find(iter->second);
1343 if (viter != m_values.end()) {
1344 return viter->second.as_optional<T>();
1345 }
1346 }
1347 return std::nullopt;
1348 }
1349#endif
1350
1351 const std::vector<KeyValue> &arguments() const { return m_sequential; }
1352
1353 const std::vector<std::string> &unmatched() const { return m_unmatched; }
1354
1355 const std::vector<KeyValue> &defaults() const { return m_defaults; }
1356
1357 const std::string arguments_string() const {
1358 std::string result;
1359 for (const auto &kv : m_sequential) {
1360 result += kv.key() + " = " + kv.value() + "\n";
1361 }
1362 for (const auto &kv : m_defaults) {
1363 result += kv.key() + " = " + kv.value() + " " + "(default)" + "\n";
1364 }
1365 return result;
1366 }
1367
1368private:
1369 NameHashMap m_keys{};
1370 ParsedHashMap m_values{};
1371 std::vector<KeyValue> m_sequential{};
1372 std::vector<KeyValue> m_defaults{};
1373 std::vector<std::string> m_unmatched{};
1374};
1375
1376struct Option {
1377 Option(std::string opts, std::string desc,
1378 std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
1379 std::string arg_help = "")
1380 : opts_(std::move(opts)), desc_(std::move(desc)),
1381 value_(std::move(value)), arg_help_(std::move(arg_help)) {}
1382
1383 std::string opts_;
1384 std::string desc_;
1385 std::shared_ptr<const Value> value_;
1386 std::string arg_help_;
1387};
1388
1390 std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
1391using PositionalList = std::vector<std::string>;
1392using PositionalListIterator = PositionalList::const_iterator;
1393
1395public:
1396 OptionParser(const OptionMap &options, const PositionalList &positional,
1397 bool allow_unrecognised)
1398 : m_options(options), m_positional(positional),
1399 m_allow_unrecognised(allow_unrecognised) {}
1400
1401 ParseResult parse(int argc, const char *const *argv);
1402
1403 bool consume_positional(const std::string &a, PositionalListIterator &next);
1404
1405 void checked_parse_arg(int argc, const char *const *argv, int &current,
1406 const std::shared_ptr<OptionDetails> &value,
1407 const std::string &name);
1408
1409 void add_to_option(const std::shared_ptr<OptionDetails> &value,
1410 const std::string &arg);
1411
1412 void parse_option(const std::shared_ptr<OptionDetails> &value,
1413 const std::string &name, const std::string &arg = "");
1414
1415 void parse_default(const std::shared_ptr<OptionDetails> &details);
1416
1417 void parse_no_value(const std::shared_ptr<OptionDetails> &details);
1418
1419private:
1420 void finalise_aliases();
1421
1422 const OptionMap &m_options;
1423 const PositionalList &m_positional;
1424
1425 std::vector<KeyValue> m_sequential{};
1426 std::vector<KeyValue> m_defaults{};
1427 bool m_allow_unrecognised;
1428
1429 ParsedHashMap m_parsed{};
1430 NameHashMap m_keys{};
1431};
1432
1433class Options {
1434public:
1435 explicit Options(std::string program_name, std::string help_string = "")
1436 : m_program(std::move(program_name)),
1437 m_help_string(toLocalString(std::move(help_string))),
1438 m_custom_help("[OPTION...]"),
1439 m_positional_help("positional parameters"), m_show_positional(false),
1440 m_allow_unrecognised(false), m_width(76), m_tab_expansion(false),
1441 m_options(std::make_shared<OptionMap>()) {}
1442
1443 Options &positional_help(std::string help_text) {
1444 m_positional_help = std::move(help_text);
1445 return *this;
1446 }
1447
1448 Options &custom_help(std::string help_text) {
1449 m_custom_help = std::move(help_text);
1450 return *this;
1451 }
1452
1454 m_show_positional = true;
1455 return *this;
1456 }
1457
1459 m_allow_unrecognised = true;
1460 return *this;
1461 }
1462
1463 Options &set_width(std::size_t width) {
1464 m_width = width;
1465 return *this;
1466 }
1467
1468 Options &set_tab_expansion(bool expansion = true) {
1469 m_tab_expansion = expansion;
1470 return *this;
1471 }
1472
1473 ParseResult parse(int argc, const char *const *argv);
1474
1475 OptionAdder add_options(std::string group = "");
1476
1477 void add_options(const std::string &group,
1478 std::initializer_list<Option> options);
1479
1480 void add_option(const std::string &group, const Option &option);
1481
1482 void add_option(const std::string &group, const std::string &s,
1483 const OptionNames &l, std::string desc,
1484 const std::shared_ptr<const Value> &value,
1485 std::string arg_help);
1486
1487 void add_option(const std::string &group, const std::string &short_name,
1488 const std::string &single_long_name, std::string desc,
1489 const std::shared_ptr<const Value> &value,
1490 std::string arg_help) {
1491 OptionNames long_names;
1492 long_names.emplace_back(single_long_name);
1493 add_option(group, short_name, long_names, desc, value, arg_help);
1494 }
1495
1496 // parse positional arguments into the given option
1497 void parse_positional(std::string option);
1498
1499 void parse_positional(std::vector<std::string> options);
1500
1501 void parse_positional(std::initializer_list<std::string> options);
1502
1503 template <typename Iterator>
1504 void parse_positional(Iterator begin, Iterator end) {
1505 parse_positional(std::vector<std::string>{begin, end});
1506 }
1507
1508 std::string help(const std::vector<std::string> &groups = {},
1509 bool print_usage = true) const;
1510
1511 std::vector<std::string> groups() const;
1512
1513 const HelpGroupDetails &group_help(const std::string &group) const;
1514
1515 const std::string &program() const { return m_program; }
1516
1517private:
1518 void add_one_option(const std::string &option,
1519 const std::shared_ptr<OptionDetails> &details);
1520
1521 String help_one_group(const std::string &group) const;
1522
1523 void generate_group_help(String &result,
1524 const std::vector<std::string> &groups) const;
1525
1526 void generate_all_groups_help(String &result) const;
1527
1528 std::string m_program{};
1529 String m_help_string{};
1530 std::string m_custom_help{};
1531 std::string m_positional_help{};
1532 bool m_show_positional;
1533 bool m_allow_unrecognised;
1534 std::size_t m_width;
1535 bool m_tab_expansion;
1536
1537 std::shared_ptr<OptionMap> m_options;
1538 std::vector<std::string> m_positional{};
1539 std::unordered_set<std::string> m_positional_set{};
1540
1541 // mapping from groups to help options
1542 std::vector<std::string> m_group{};
1543 std::map<std::string, HelpGroupDetails> m_help{};
1544};
1545
1547public:
1548 OptionAdder(Options &options, std::string group)
1549 : m_options(options), m_group(std::move(group)) {}
1550
1552 const std::string &opts, const std::string &desc,
1553 const std::shared_ptr<const Value> &value = ::cxxopts::value<bool>(),
1554 std::string arg_help = "");
1555
1556private:
1557 Options &m_options;
1558 std::string m_group;
1559};
1560
1561namespace {
1562constexpr std::size_t OPTION_LONGEST = 30;
1563constexpr std::size_t OPTION_DESC_GAP = 2;
1564
1565String format_option(const HelpOptionDetails &o) {
1566 const auto &s = o.s;
1567 const auto &l = first_or_empty(o.l);
1568
1569 String result = " ";
1570
1571 if (!s.empty()) {
1572 result += "-" + toLocalString(s);
1573 if (!l.empty()) {
1574 result += ",";
1575 }
1576 } else {
1577 result += " ";
1578 }
1579
1580 if (!l.empty()) {
1581 result += " --" + toLocalString(l);
1582 }
1583
1584 auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg";
1585
1586 if (!o.is_boolean) {
1587 if (o.has_implicit) {
1588 result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
1589 } else {
1590 result += " " + arg;
1591 }
1592 }
1593
1594 return result;
1595}
1596
1597String format_description(const HelpOptionDetails &o, std::size_t start,
1598 std::size_t allowed, bool tab_expansion) {
1599 auto desc = o.desc;
1600
1601 if (o.has_default && (!o.is_boolean || o.default_value != "false")) {
1602 if (!o.default_value.empty()) {
1603 desc += toLocalString(" (default: " + o.default_value + ")");
1604 } else {
1605 desc += toLocalString(" (default: \"\")");
1606 }
1607 }
1608
1609 String result;
1610
1611 if (tab_expansion) {
1612 String desc2;
1613 auto size = std::size_t{0};
1614 for (auto c = std::begin(desc); c != std::end(desc); ++c) {
1615 if (*c == '\n') {
1616 desc2 += *c;
1617 size = 0;
1618 } else if (*c == '\t') {
1619 auto skip = 8 - size % 8;
1620 stringAppend(desc2, skip, ' ');
1621 size += skip;
1622 } else {
1623 desc2 += *c;
1624 ++size;
1625 }
1626 }
1627 desc = desc2;
1628 }
1629
1630 desc += " ";
1631
1632 auto current = std::begin(desc);
1633 auto previous = current;
1634 auto startLine = current;
1635 auto lastSpace = current;
1636
1637 auto size = std::size_t{};
1638
1639 bool appendNewLine;
1640 bool onlyWhiteSpace = true;
1641
1642 while (current != std::end(desc)) {
1643 appendNewLine = false;
1644 if (*previous == ' ' || *previous == '\t') {
1645 lastSpace = current;
1646 }
1647 if (*current != ' ' && *current != '\t') {
1648 onlyWhiteSpace = false;
1649 }
1650
1651 while (*current == '\n') {
1652 previous = current;
1653 ++current;
1654 appendNewLine = true;
1655 }
1656
1657 if (!appendNewLine && size >= allowed) {
1658 if (lastSpace != startLine) {
1659 current = lastSpace;
1660 previous = current;
1661 }
1662 appendNewLine = true;
1663 }
1664
1665 if (appendNewLine) {
1666 stringAppend(result, startLine, current);
1667 startLine = current;
1668 lastSpace = current;
1669
1670 if (*previous != '\n') {
1671 stringAppend(result, "\n");
1672 }
1673
1674 stringAppend(result, start, ' ');
1675
1676 if (*previous != '\n') {
1677 stringAppend(result, lastSpace, current);
1678 }
1679
1680 onlyWhiteSpace = true;
1681 size = 0;
1682 }
1683
1684 previous = current;
1685 ++current;
1686 ++size;
1687 }
1688
1689 // append whatever is left but ignore whitespace
1690 if (!onlyWhiteSpace) {
1691 stringAppend(result, startLine, previous);
1692 }
1693
1694 return result;
1695}
1696
1697} // namespace
1698
1699inline void Options::add_options(const std::string &group,
1700 std::initializer_list<Option> options) {
1701 OptionAdder option_adder(*this, group);
1702 for (const auto &option : options) {
1703 option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
1704 }
1705}
1706
1707inline OptionAdder Options::add_options(std::string group) {
1708 return OptionAdder(*this, std::move(group));
1709}
1710
1711inline OptionAdder &
1712OptionAdder::operator()(const std::string &opts, const std::string &desc,
1713 const std::shared_ptr<const Value> &value,
1714 std::string arg_help) {
1716 // Note: All names will be non-empty; but we must separate the short
1717 // (length-1) and longer names
1718 std::string short_name{""};
1719 auto first_short_name_iter = std::partition(
1720 option_names.begin(), option_names.end(),
1721 [&](const std::string &name) { return name.length() > 1; });
1722 auto num_length_1_names = (option_names.end() - first_short_name_iter);
1723 switch (num_length_1_names) {
1724 case 1:
1725 short_name = *first_short_name_iter;
1726 option_names.erase(first_short_name_iter);
1728 case 0:
1729 break;
1730 default:
1731 throw_or_mimic<exceptions::invalid_option_format>(opts);
1732 };
1733
1734 m_options.add_option(m_group, short_name, option_names, desc, value,
1735 std::move(arg_help));
1736
1737 return *this;
1738}
1739
1740inline void
1741OptionParser::parse_default(const std::shared_ptr<OptionDetails> &details) {
1742 // TODO: remove the duplicate code here
1743 auto &store = m_parsed[details->hash()];
1744 store.parse_default(details);
1745 m_defaults.emplace_back(details->essential_name(),
1746 details->value().get_default_value());
1747}
1748
1749inline void
1750OptionParser::parse_no_value(const std::shared_ptr<OptionDetails> &details) {
1751 auto &store = m_parsed[details->hash()];
1752 store.parse_no_value(details);
1753}
1754
1755inline void
1756OptionParser::parse_option(const std::shared_ptr<OptionDetails> &value,
1757 const std::string & /*name*/,
1758 const std::string &arg) {
1759 auto hash = value->hash();
1760 auto &result = m_parsed[hash];
1761 result.parse(value, arg);
1762
1763 m_sequential.emplace_back(value->essential_name(), arg);
1764}
1765
1766inline void
1767OptionParser::checked_parse_arg(int argc, const char *const *argv, int &current,
1768 const std::shared_ptr<OptionDetails> &value,
1769 const std::string &name) {
1770 if (current + 1 >= argc) {
1771 if (value->value().has_implicit()) {
1772 parse_option(value, name, value->value().get_implicit_value());
1773 } else {
1774 throw_or_mimic<exceptions::missing_argument>(name);
1775 }
1776 } else {
1777 if (value->value().has_implicit()) {
1778 parse_option(value, name, value->value().get_implicit_value());
1779 } else {
1780 parse_option(value, name, argv[current + 1]);
1781 ++current;
1782 }
1783 }
1784}
1785
1786inline void
1787OptionParser::add_to_option(const std::shared_ptr<OptionDetails> &value,
1788 const std::string &arg) {
1789 auto hash = value->hash();
1790 auto &result = m_parsed[hash];
1791 result.add(value, arg);
1792
1793 m_sequential.emplace_back(value->essential_name(), arg);
1794}
1795
1796inline bool OptionParser::consume_positional(const std::string &a,
1797 PositionalListIterator &next) {
1798 while (next != m_positional.end()) {
1799 auto iter = m_options.find(*next);
1800 if (iter != m_options.end()) {
1801 if (!iter->second->value().is_container()) {
1802 auto &result = m_parsed[iter->second->hash()];
1803 if (result.count() == 0) {
1804 add_to_option(iter->second, a);
1805 ++next;
1806 return true;
1807 }
1808 ++next;
1809 continue;
1810 }
1811 add_to_option(iter->second, a);
1812 return true;
1813 }
1814 throw_or_mimic<exceptions::no_such_option>(*next);
1815 }
1816
1817 return false;
1818}
1819
1820inline void Options::parse_positional(std::string option) {
1821 parse_positional(std::vector<std::string>{std::move(option)});
1822}
1823
1824inline void Options::parse_positional(std::vector<std::string> options) {
1825 m_positional = std::move(options);
1826
1827 m_positional_set.insert(m_positional.begin(), m_positional.end());
1828}
1829
1830inline void
1831Options::parse_positional(std::initializer_list<std::string> options) {
1832 parse_positional(std::vector<std::string>(options));
1833}
1834
1835inline ParseResult Options::parse(int argc, const char *const *argv) {
1836 OptionParser parser(*m_options, m_positional, m_allow_unrecognised);
1837
1838 return parser.parse(argc, argv);
1839}
1840
1841inline ParseResult OptionParser::parse(int argc, const char *const *argv) {
1842 int current = 1;
1843 bool consume_remaining = false;
1844 auto next_positional = m_positional.begin();
1845
1846 std::vector<std::string> unmatched;
1847
1848 while (current != argc) {
1849 if (strcmp(argv[current], "--") == 0) {
1850 consume_remaining = true;
1851 ++current;
1852 break;
1853 }
1854 bool matched = false;
1856 values::parser_tool::ParseArgument(argv[current], matched);
1857
1858 if (!matched) {
1859 // not a flag
1860
1861 // but if it starts with a `-`, then it's an error
1862 if (argv[current][0] == '-' && argv[current][1] != '\0') {
1863 if (!m_allow_unrecognised) {
1864 throw_or_mimic<exceptions::invalid_option_syntax>(argv[current]);
1865 }
1866 }
1867
1868 // if true is returned here then it was consumed, otherwise it is
1869 // ignored
1870 if (consume_positional(argv[current], next_positional)) {
1871 } else {
1872 unmatched.emplace_back(argv[current]);
1873 }
1874 // if we return from here then it was parsed successfully, so continue
1875 } else {
1876 // short or long option?
1877 if (argu_desc.grouping) {
1878 const std::string &s = argu_desc.arg_name;
1879
1880 for (std::size_t i = 0; i != s.size(); ++i) {
1881 std::string name(1, s[i]);
1882 auto iter = m_options.find(name);
1883
1884 if (iter == m_options.end()) {
1885 if (m_allow_unrecognised) {
1886 unmatched.push_back(std::string("-") + s[i]);
1887 continue;
1888 }
1889 // error
1890 throw_or_mimic<exceptions::no_such_option>(name);
1891 }
1892
1893 auto value = iter->second;
1894
1895 if (i + 1 == s.size()) {
1896 // it must be the last argument
1897 checked_parse_arg(argc, argv, current, value, name);
1898 } else if (value->value().has_implicit()) {
1899 parse_option(value, name, value->value().get_implicit_value());
1900 } else if (i + 1 < s.size()) {
1901 std::string arg_value = s.substr(i + 1);
1902 parse_option(value, name, arg_value);
1903 break;
1904 } else {
1905 // error
1906 throw_or_mimic<exceptions::option_requires_argument>(name);
1907 }
1908 }
1909 } else if (argu_desc.arg_name.length() != 0) {
1910 const std::string &name = argu_desc.arg_name;
1911
1912 auto iter = m_options.find(name);
1913
1914 if (iter == m_options.end()) {
1915 if (m_allow_unrecognised) {
1916 // keep unrecognised options in argument list, skip to next argument
1917 unmatched.emplace_back(argv[current]);
1918 ++current;
1919 continue;
1920 }
1921 // error
1922 throw_or_mimic<exceptions::no_such_option>(name);
1923 }
1924
1925 auto opt = iter->second;
1926
1927 // equals provided for long option?
1928 if (argu_desc.set_value) {
1929 // parse the option given
1930
1931 parse_option(opt, name, argu_desc.value);
1932 } else {
1933 // parse the next argument
1934 checked_parse_arg(argc, argv, current, opt, name);
1935 }
1936 }
1937 }
1938
1939 ++current;
1940 }
1941
1942 for (auto &opt : m_options) {
1943 auto &detail = opt.second;
1944 const auto &value = detail->value();
1945
1946 auto &store = m_parsed[detail->hash()];
1947
1948 if (value.has_default()) {
1949 if (!store.count() && !store.has_default()) {
1950 parse_default(detail);
1951 }
1952 } else {
1953 parse_no_value(detail);
1954 }
1955 }
1956
1957 if (consume_remaining) {
1958 while (current < argc) {
1959 if (!consume_positional(argv[current], next_positional)) {
1960 break;
1961 }
1962 ++current;
1963 }
1964
1965 // adjust argv for any that couldn't be swallowed
1966 while (current != argc) {
1967 unmatched.emplace_back(argv[current]);
1968 ++current;
1969 }
1970 }
1971
1972 finalise_aliases();
1973
1974 ParseResult parsed(std::move(m_keys), std::move(m_parsed),
1975 std::move(m_sequential), std::move(m_defaults),
1976 std::move(unmatched));
1977 return parsed;
1978}
1979
1980inline void OptionParser::finalise_aliases() {
1981 for (auto &option : m_options) {
1982 auto &detail = *option.second;
1983 auto hash = detail.hash();
1984 m_keys[detail.short_name()] = hash;
1985 for (const auto &long_name : detail.long_names()) {
1986 m_keys[long_name] = hash;
1987 }
1988
1989 m_parsed.emplace(hash, OptionValue());
1990 }
1991}
1992
1993inline void Options::add_option(const std::string &group,
1994 const Option &option) {
1995 add_options(group, {option});
1996}
1997
1998inline void Options::add_option(const std::string &group, const std::string &s,
1999 const OptionNames &l, std::string desc,
2000 const std::shared_ptr<const Value> &value,
2001 std::string arg_help) {
2002 auto stringDesc = toLocalString(std::move(desc));
2003 auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
2004
2005 if (!s.empty()) {
2006 add_one_option(s, option);
2007 }
2008
2009 for (const auto &long_name : l) {
2010 add_one_option(long_name, option);
2011 }
2012
2013 // add the help details
2014
2015 if (m_help.find(group) == m_help.end()) {
2016 m_group.push_back(group);
2017 }
2018
2019 auto &options = m_help[group];
2020
2021 options.options.emplace_back(HelpOptionDetails{
2022 s, l, stringDesc, value->has_default(), value->get_default_value(),
2023 value->has_implicit(), value->get_implicit_value(), std::move(arg_help),
2024 value->is_container(), value->is_boolean()});
2025}
2026
2027inline void
2028Options::add_one_option(const std::string &option,
2029 const std::shared_ptr<OptionDetails> &details) {
2030 auto in = m_options->emplace(option, details);
2031
2032 if (!in.second) {
2033 throw_or_mimic<exceptions::option_already_exists>(option);
2034 }
2035}
2036
2037inline String Options::help_one_group(const std::string &g) const {
2038 using OptionHelp = std::vector<std::pair<String, String>>;
2039
2040 auto group = m_help.find(g);
2041 if (group == m_help.end()) {
2042 return "";
2043 }
2044
2045 OptionHelp format;
2046
2047 std::size_t longest = 0;
2048
2049 String result;
2050
2051 if (!g.empty()) {
2052 result += toLocalString(" " + g + " options:\n");
2053 }
2054
2055 for (const auto &o : group->second.options) {
2056 if (o.l.size() &&
2057 m_positional_set.find(o.l.front()) != m_positional_set.end() &&
2058 !m_show_positional) {
2059 continue;
2060 }
2061
2062 auto s = format_option(o);
2063 longest = (std::max)(longest, stringLength(s));
2064 format.push_back(std::make_pair(s, String()));
2065 }
2066 longest = (std::min)(longest, OPTION_LONGEST);
2067
2068 // widest allowed description -- min 10 chars for helptext/line
2069 std::size_t allowed = 10;
2070 if (m_width > allowed + longest + OPTION_DESC_GAP) {
2071 allowed = m_width - longest - OPTION_DESC_GAP;
2072 }
2073
2074 auto fiter = format.begin();
2075 for (const auto &o : group->second.options) {
2076 if (o.l.size() &&
2077 m_positional_set.find(o.l.front()) != m_positional_set.end() &&
2078 !m_show_positional) {
2079 continue;
2080 }
2081
2082 auto d = format_description(o, longest + OPTION_DESC_GAP, allowed,
2083 m_tab_expansion);
2084
2085 result += fiter->first;
2086 if (stringLength(fiter->first) > longest) {
2087 result += '\n';
2088 result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
2089 } else {
2090 result += toLocalString(std::string(
2091 longest + OPTION_DESC_GAP - stringLength(fiter->first), ' '));
2092 }
2093 result += d;
2094 result += '\n';
2095
2096 ++fiter;
2097 }
2098
2099 return result;
2100}
2101
2102inline void Options::generate_group_help(
2103 String &result, const std::vector<std::string> &print_groups) const {
2104 for (std::size_t i = 0; i != print_groups.size(); ++i) {
2105 const String &group_help_text = help_one_group(print_groups[i]);
2106 if (empty(group_help_text)) {
2107 continue;
2108 }
2109 result += group_help_text;
2110 if (i < print_groups.size() - 1) {
2111 result += '\n';
2112 }
2113 }
2114}
2115
2116inline void Options::generate_all_groups_help(String &result) const {
2117 generate_group_help(result, m_group);
2118}
2119
2120inline std::string Options::help(const std::vector<std::string> &help_groups,
2121 bool print_usage) const {
2122 String result = m_help_string;
2123 if (print_usage) {
2124 result += "\nUsage:\n " + toLocalString(m_program);
2125 }
2126
2127 if (!m_custom_help.empty()) {
2128 result += " " + toLocalString(m_custom_help);
2129 }
2130
2131 if (!m_positional.empty() && !m_positional_help.empty()) {
2132 result += " " + toLocalString(m_positional_help);
2133 }
2134
2135 result += "\n\n";
2136
2137 if (help_groups.empty()) {
2138 generate_all_groups_help(result);
2139 } else {
2140 generate_group_help(result, help_groups);
2141 }
2142
2143 return toUTF8String(result);
2144}
2145
2146inline std::vector<std::string> Options::groups() const { return m_group; }
2147
2148inline const HelpGroupDetails &
2149Options::group_help(const std::string &group) const {
2150 return m_help.at(group);
2151}
2152
2153} // namespace cxxopts
2154
2155#endif // CXXOPTS_HPP_INCLUDED
CXXOPTS_NODISCARD const std::string & key() const
Definition cxxopts.hpp:1198
KeyValue(std::string key_, std::string value_) noexcept
Definition cxxopts.hpp:1194
CXXOPTS_NODISCARD const std::string & value() const
Definition cxxopts.hpp:1201
OptionAdder & operator()(const std::string &opts, const std::string &desc, const std::shared_ptr< const Value > &value=::cxxopts::value< bool >(), std::string arg_help="")
Definition cxxopts.hpp:1712
OptionAdder(Options &options, std::string group)
Definition cxxopts.hpp:1548
CXXOPTS_NODISCARD const std::string & essential_name() const
Definition cxxopts.hpp:1074
CXXOPTS_NODISCARD const OptionNames & long_names() const
Definition cxxopts.hpp:1079
std::size_t hash() const
Definition cxxopts.hpp:1081
CXXOPTS_NODISCARD const Value & value() const
Definition cxxopts.hpp:1062
CXXOPTS_NODISCARD std::shared_ptr< Value > make_storage() const
Definition cxxopts.hpp:1065
CXXOPTS_NODISCARD const String & description() const
Definition cxxopts.hpp:1059
OptionDetails(const OptionDetails &rhs)
Definition cxxopts.hpp:1052
OptionDetails(std::string short_, OptionNames long_, String desc, std::shared_ptr< const Value > val)
Definition cxxopts.hpp:1045
CXXOPTS_NODISCARD const std::string & first_long_name() const
Definition cxxopts.hpp:1071
CXXOPTS_NODISCARD const std::string & short_name() const
Definition cxxopts.hpp:1068
OptionDetails(OptionDetails &&rhs)=default
void parse_option(const std::shared_ptr< OptionDetails > &value, const std::string &name, const std::string &arg="")
Definition cxxopts.hpp:1756
OptionParser(const OptionMap &options, const PositionalList &positional, bool allow_unrecognised)
Definition cxxopts.hpp:1396
void checked_parse_arg(int argc, const char *const *argv, int &current, const std::shared_ptr< OptionDetails > &value, const std::string &name)
Definition cxxopts.hpp:1767
void parse_default(const std::shared_ptr< OptionDetails > &details)
Definition cxxopts.hpp:1741
ParseResult parse(int argc, const char *const *argv)
Definition cxxopts.hpp:1841
bool consume_positional(const std::string &a, PositionalListIterator &next)
Definition cxxopts.hpp:1796
void add_to_option(const std::shared_ptr< OptionDetails > &value, const std::string &arg)
Definition cxxopts.hpp:1787
void parse_no_value(const std::shared_ptr< OptionDetails > &details)
Definition cxxopts.hpp:1750
void parse_default(const std::shared_ptr< const OptionDetails > &details)
Definition cxxopts.hpp:1130
const T & as() const
Definition cxxopts.hpp:1158
void parse(const std::shared_ptr< const OptionDetails > &details, const std::string &text)
Definition cxxopts.hpp:1122
void parse_no_value(const std::shared_ptr< const OptionDetails > &details)
Definition cxxopts.hpp:1137
CXXOPTS_NODISCARD std::size_t count() const noexcept
Definition cxxopts.hpp:1147
CXXOPTS_NODISCARD bool has_default() const noexcept
Definition cxxopts.hpp:1155
void add(const std::shared_ptr< const OptionDetails > &details, const std::string &text)
Definition cxxopts.hpp:1114
std::string help(const std::vector< std::string > &groups={}, bool print_usage=true) const
Definition cxxopts.hpp:2120
void parse_positional(std::string option)
Definition cxxopts.hpp:1820
Options & set_width(std::size_t width)
Definition cxxopts.hpp:1463
void parse_positional(Iterator begin, Iterator end)
Definition cxxopts.hpp:1504
ParseResult parse(int argc, const char *const *argv)
Definition cxxopts.hpp:1835
Options & show_positional_help()
Definition cxxopts.hpp:1453
std::vector< std::string > groups() const
Definition cxxopts.hpp:2146
Options(std::string program_name, std::string help_string="")
Definition cxxopts.hpp:1435
OptionAdder add_options(std::string group="")
Definition cxxopts.hpp:1707
Options & set_tab_expansion(bool expansion=true)
Definition cxxopts.hpp:1468
Options & allow_unrecognised_options()
Definition cxxopts.hpp:1458
const std::string & program() const
Definition cxxopts.hpp:1515
const HelpGroupDetails & group_help(const std::string &group) const
Definition cxxopts.hpp:2149
void add_option(const std::string &group, const Option &option)
Definition cxxopts.hpp:1993
void add_option(const std::string &group, const std::string &short_name, const std::string &single_long_name, std::string desc, const std::shared_ptr< const Value > &value, std::string arg_help)
Definition cxxopts.hpp:1487
Options & custom_help(std::string help_text)
Definition cxxopts.hpp:1448
Options & positional_help(std::string help_text)
Definition cxxopts.hpp:1443
std::forward_iterator_tag iterator_category
Definition cxxopts.hpp:1222
bool operator!=(const Iterator &other) const
Definition cxxopts.hpp:1271
Iterator(const Iterator &)=default
bool operator==(const Iterator &other) const
Definition cxxopts.hpp:1267
CXXOPTS_DIAGNOSTIC_POP Iterator & operator++()
Definition cxxopts.hpp:1251
const KeyValue & operator*()
Definition cxxopts.hpp:1273
const KeyValue * operator->()
Definition cxxopts.hpp:1275
Iterator begin() const
Definition cxxopts.hpp:1298
ParseResult(NameHashMap &&keys, ParsedHashMap &&values, std::vector< KeyValue > sequential, std::vector< KeyValue > default_opts, std::vector< std::string > &&unmatched_args)
Definition cxxopts.hpp:1286
ParseResult(const ParseResult &)=default
ParseResult & operator=(ParseResult &&)=default
std::size_t count(const std::string &o) const
Definition cxxopts.hpp:1302
Iterator end() const
Definition cxxopts.hpp:1300
bool contains(const std::string &o) const
Definition cxxopts.hpp:1317
const OptionValue & operator[](const std::string &option) const
Definition cxxopts.hpp:1321
const std::vector< KeyValue > & arguments() const
Definition cxxopts.hpp:1351
const std::vector< std::string > & unmatched() const
Definition cxxopts.hpp:1353
const std::vector< KeyValue > & defaults() const
Definition cxxopts.hpp:1355
const std::string arguments_string() const
Definition cxxopts.hpp:1357
ParseResult & operator=(const ParseResult &)=default
virtual std::shared_ptr< Value > clone() const =0
virtual std::string get_default_value() const =0
virtual void parse(const std::string &text) const =0
virtual std::string get_implicit_value() const =0
virtual std::shared_ptr< Value > no_implicit_value()=0
virtual bool is_container() const =0
virtual bool is_boolean() const =0
virtual void parse() const =0
virtual std::shared_ptr< Value > default_value(const std::string &value)=0
virtual bool has_default() const =0
virtual bool has_implicit() const =0
virtual void add(const std::string &text) const =0
virtual std::shared_ptr< Value > implicit_value(const std::string &value)=0
virtual ~Value()=default
exception(std::string message)
Definition cxxopts.hpp:335
CXXOPTS_NODISCARD const char * what() const noexcept override
Definition cxxopts.hpp:338
gratuitous_argument_for_option(const std::string &option, const std::string &arg)
Definition cxxopts.hpp:396
incorrect_argument_type(const std::string &arg)
Definition cxxopts.hpp:419
invalid_option_format(const std::string &format)
Definition cxxopts.hpp:363
invalid_option_syntax(const std::string &text)
Definition cxxopts.hpp:369
missing_argument(const std::string &option)
Definition cxxopts.hpp:382
no_such_option(const std::string &option)
Definition cxxopts.hpp:376
option_already_exists(const std::string &option)
Definition cxxopts.hpp:356
option_has_no_value(const std::string &option)
Definition cxxopts.hpp:411
option_requires_argument(const std::string &option)
Definition cxxopts.hpp:389
parsing(const std::string &message)
Definition cxxopts.hpp:351
requested_option_not_present(const std::string &option)
Definition cxxopts.hpp:405
specification(const std::string &message)
Definition cxxopts.hpp:346
std::shared_ptr< T > m_result
Definition cxxopts.hpp:977
bool is_container() const override
Definition cxxopts.hpp:938
std::shared_ptr< Value > no_implicit_value() override
Definition cxxopts.hpp:958
std::shared_ptr< Value > default_value(const std::string &value) override
Definition cxxopts.hpp:946
abstract_value(const abstract_value &rhs)
Definition cxxopts.hpp:916
std::string get_implicit_value() const override
Definition cxxopts.hpp:965
bool has_default() const override
Definition cxxopts.hpp:942
std::string get_default_value() const override
Definition cxxopts.hpp:963
void parse() const override
Definition cxxopts.hpp:940
std::shared_ptr< Value > implicit_value(const std::string &value) override
Definition cxxopts.hpp:952
bool is_boolean() const override
Definition cxxopts.hpp:967
void parse(const std::string &text) const override
Definition cxxopts.hpp:934
void add(const std::string &text) const override
Definition cxxopts.hpp:930
~abstract_value() override=default
abstract_value & operator=(const abstract_value &)=default
bool has_implicit() const override
Definition cxxopts.hpp:944
std::shared_ptr< Value > clone() const override
Definition cxxopts.hpp:1010
CXXOPTS_NODISCARD std::shared_ptr< Value > clone() const override
Definition cxxopts.hpp:993
#define CXXOPTS__VERSION_MAJOR
Definition cxxopts.hpp:103
#define CXXOPTS_LINKONCE
Definition cxxopts.hpp:61
#define CXXOPTS_VECTOR_DELIMITER
Definition cxxopts.hpp:100
#define CXXOPTS_NODISCARD
Definition cxxopts.hpp:96
#define CXXOPTS_FALLTHROUGH
Definition cxxopts.hpp:85
#define CXXOPTS_IGNORE_WARNING(x)
Definition cxxopts.hpp:120
#define CXXOPTS__VERSION_MINOR
Definition cxxopts.hpp:104
#define CXXOPTS__VERSION_PATCH
Definition cxxopts.hpp:105
#define CXXOPTS_LINKONCE_CONST
Definition cxxopts.hpp:60
#define CXXOPTS_DIAGNOSTIC_POP
Definition cxxopts.hpp:119
#define CXXOPTS_DIAGNOSTIC_PUSH
Definition cxxopts.hpp:118
void check_signed_range(bool negative, U value, const std::string &text)
Definition cxxopts.hpp:726
ArguDesc ParseArgument(const char *arg, bool &matched)
Definition cxxopts.hpp:674
bool IsTrueText(const std::string &text)
Definition cxxopts.hpp:637
OptionNames split_option_names(const std::string &text)
Definition cxxopts.hpp:654
IntegerDesc SplitInteger(const std::string &text)
Definition cxxopts.hpp:613
bool IsFalseText(const std::string &text)
Definition cxxopts.hpp:644
void integer_parser(const std::string &text, T &value)
Definition cxxopts.hpp:746
void checked_negate(R &r, T &&t, const std::string &, std::true_type)
Definition cxxopts.hpp:733
void stringstream_parser(const std::string &text, T &value)
Definition cxxopts.hpp:800
void parse_value(const std::string &text, T &value)
Definition cxxopts.hpp:810
void add_value(const std::string &text, T &value)
Definition cxxopts.hpp:882
std::string String
Definition cxxopts.hpp:250
std::string toUTF8String(T &&t)
Definition cxxopts.hpp:271
bool empty(const std::string &s)
Definition cxxopts.hpp:275
void throw_or_mimic(const std::string &text)
Definition cxxopts.hpp:426
std::vector< std::string > OptionNames
Definition cxxopts.hpp:443
CXXOPTS_NODISCARD const std::string & first_or_empty(const OptionNames &long_names)
Definition cxxopts.hpp:1038
std::size_t stringLength(const String &s)
Definition cxxopts.hpp:257
std::unordered_map< std::size_t, OptionValue > ParsedHashMap
Definition cxxopts.hpp:1215
std::shared_ptr< Value > value()
Definition cxxopts.hpp:1026
uint8_t patch
Definition cxxopts.hpp:131
PositionalList::const_iterator PositionalListIterator
Definition cxxopts.hpp:1392
std::vector< std::string > PositionalList
Definition cxxopts.hpp:1391
std::unordered_map< std::string, std::size_t > NameHashMap
Definition cxxopts.hpp:1216
T toLocalString(T &&t)
Definition cxxopts.hpp:253
std::unordered_map< std::string, std::shared_ptr< OptionDetails > > OptionMap
Definition cxxopts.hpp:1390
uint8_t major
Definition cxxopts.hpp:131
String & stringAppend(String &s, const String &a)
Definition cxxopts.hpp:259
uint8_t minor
Definition cxxopts.hpp:131
bool operator!=(const Port &rhs) const
Definition AIEDialect.h:126
bool operator==(const Port &rhs) const
Definition AIEDialect.h:122
std::vector< HelpOptionDetails > options
Definition cxxopts.hpp:1109
std::shared_ptr< const Value > value_
Definition cxxopts.hpp:1385
Option(std::string opts, std::string desc, std::shared_ptr< const Value > value=::cxxopts::value< bool >(), std::string arg_help="")
Definition cxxopts.hpp:1377
std::string arg_help_
Definition cxxopts.hpp:1386
std::string opts_
Definition cxxopts.hpp:1383
std::string desc_
Definition cxxopts.hpp:1384
void operator()(bool, U, const std::string &) const
Definition cxxopts.hpp:722
void operator()(bool negative, U u, const std::string &text)
Definition cxxopts.hpp:706
static constexpr bool value
Definition cxxopts.hpp:895