From: Matthew Sloyan Date: Tue, 6 Oct 2020 15:06:07 +0000 (+0100) Subject: IVGCVSW-4488 Update cxxopts to version 3.0 X-Git-Tag: submit/tizen/20210421.062230~280 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=84dc8430432c0a65c2fdc8946e06d307d18df28d;p=platform%2Fupstream%2Farmnn.git IVGCVSW-4488 Update cxxopts to version 3.0 * Required to fix issue in TfLiteMobilenetQuantized-Armnn.cpp Signed-off-by: Matthew Sloyan Change-Id: I3a465f62e3d656c9626113da6223e4fa26b535a6 --- diff --git a/third-party/cxxopts/CHANGELOG.md b/third-party/cxxopts/CHANGELOG.md index 4bddcff..df0e110 100644 --- a/third-party/cxxopts/CHANGELOG.md +++ b/third-party/cxxopts/CHANGELOG.md @@ -3,7 +3,7 @@ This is the changelog for `cxxopts`, a C++11 library for parsing command line options. The project adheres to semantic versioning. -## Next version +## 3.0 ### Changed @@ -12,6 +12,13 @@ options. The project adheres to semantic versioning. * Fix duplicate default options when there is a short and long option. * Add `CXXOPTS_NO_EXCEPTIONS` to disable exceptions. * Fix char parsing for space and check for length. +* Change argument type in `Options::parse` from `char**` to `const char**`. +* Refactor parser to not change its arguments. +* `ParseResult` doesn't depend on a reference to the parser. + +### Added + +* A list of unmatched arguments is available in `ParseResult`. ## 2.2 diff --git a/third-party/cxxopts/README.md b/third-party/cxxopts/README.md index f157052..9517993 100644 --- a/third-party/cxxopts/README.md +++ b/third-party/cxxopts/README.md @@ -5,6 +5,25 @@ Note that `master` is generally a work in progress, and you probably want to use a tagged release version. +## Version 3 breaking changes + +If you have used version 2, there are a couple of breaking changes in (the as +yet unreleased, current master) version 3 that you should be aware of. If you are new to +`cxxopts` you can skip this section. + +The parser no longer modifies its arguments, so you can pass a const `argc` and +`argv` and expect them not to be changed. + +The `ParseResult` object no longer depends on the parser. So it can be returned +from a scope outside the parser and still work. Now that the inputs are not +modified, `ParseResult` stores a list of the unmatched arguments. These are +retrieved like follows: + +```cpp +auto result = options.parse(argc, argv); +result.unmatched(); // get the unmatched arguments +``` + # Quick start This is a lightweight C++ option parser library, supporting the standard GNU @@ -69,6 +88,23 @@ exception will be thrown. Note that the result of `options.parse` should only be used as long as the `options` object that created it is in scope. +## Unrecognised arguments + +You can allow unrecognised arguments to be skipped. This applies to both +positional arguments that are not parsed into another option, and `--` +arguments that do not match an argument that you specify. This is done by +calling: + +```cpp +options.allow_unrecognised_options(); +``` + +and in the result object they are retrieved with: + +```cpp +result.unmatched() +``` + ## Exceptions Exceptional situations throw C++ exceptions. There are two types of @@ -146,6 +182,22 @@ that can be parsed as a `std::vector`: --my_list=1,-2.1,3,4.5 ~~~ +## Options specified multiple times + +The same option can be specified several times, with different arguments, which will all +be recorded in order of appearance. An example: + +~~~ +--use train --use bus --use ferry +~~~ + +this is supported through the use of a vector of value for the option: + +~~~ +options.add_options() + ("use", "Usable means of transport", cxxopts::value>()) +~~~ + ## Custom help The string after the program name on the first line of the help can be diff --git a/third-party/cxxopts/cxxopts.hpp b/third-party/cxxopts/cxxopts.hpp index 97381a9..88e8a02 100644 --- a/third-party/cxxopts/cxxopts.hpp +++ b/third-party/cxxopts/cxxopts.hpp @@ -30,6 +30,7 @@ THE SOFTWARE. #include #include #include +#include #include #include #include @@ -45,12 +46,18 @@ THE SOFTWARE. #define CXXOPTS_HAS_OPTIONAL #endif +#if __cplusplus >= 201603L +#define CXXOPTS_NODISCARD [[nodiscard]] +#else +#define CXXOPTS_NODISCARD +#endif + #ifndef CXXOPTS_VECTOR_DELIMITER #define CXXOPTS_VECTOR_DELIMITER ',' #endif -#define CXXOPTS__VERSION_MAJOR 2 -#define CXXOPTS__VERSION_MINOR 2 +#define CXXOPTS__VERSION_MAJOR 3 +#define CXXOPTS__VERSION_MINOR 0 #define CXXOPTS__VERSION_PATCH 0 namespace cxxopts @@ -140,9 +147,9 @@ namespace cxxopts inline String& - stringAppend(String& s, int n, UChar32 c) + stringAppend(String& s, size_t n, UChar32 c) { - for (int i = 0; i != n; ++i) + for (size_t i = 0; i != n; ++i) { s.append(c); } @@ -278,6 +285,13 @@ namespace cxxopts #endif } // namespace +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic push +// This will be ignored under other compilers like LLVM clang. +#endif class Value : public std::enable_shared_from_this { public: @@ -321,7 +335,9 @@ namespace cxxopts virtual bool is_boolean() const = 0; }; - +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif class OptionException : public std::exception { public: @@ -330,6 +346,7 @@ namespace cxxopts { } + CXXOPTS_NODISCARD const char* what() const noexcept override { @@ -443,6 +460,18 @@ namespace cxxopts } }; + class option_has_no_value_exception : public OptionException + { + public: + explicit option_has_no_value_exception(const std::string& option) + : OptionException( + option.empty() ? + ("Option " + LQUOTE + option + RQUOTE + " has no value") : + "Option has no value") + { + } + }; + class argument_incorrect_type : public OptionParseException { public: @@ -545,21 +574,20 @@ namespace cxxopts } // namespace detail template - R - checked_negate(T&& t, const std::string&, std::true_type) + void + checked_negate(R& r, T&& t, const std::string&, std::true_type) { // if we got to here, then `t` is a positive number that fits into // `R`. So to avoid MSVC C4146, we first cast it to `R`. // See https://github.com/jarro2783/cxxopts/issues/62 for more details. - return static_cast(-static_cast(t-1)-1); + r = static_cast(-static_cast(t-1)-1); } template - T - checked_negate(T&& t, const std::string& text, std::false_type) + void + checked_negate(R&, T&&, const std::string& text, std::false_type) { throw_or_mimic(text); - return t; } template @@ -624,9 +652,7 @@ namespace cxxopts if (negative) { - value = checked_negate(result, - text, - std::integral_constant()); + checked_negate(value, result, text, std::integral_constant()); } else { @@ -805,6 +831,8 @@ namespace cxxopts ~abstract_value() override = default; + abstract_value& operator=(const abstract_value&) = default; + abstract_value(const abstract_value& rhs) { if (rhs.m_result) @@ -905,14 +933,14 @@ namespace cxxopts } protected: - std::shared_ptr m_result; - T* m_store; + std::shared_ptr m_result{}; + T* m_store{}; bool m_default = false; bool m_implicit = false; - std::string m_default_value; - std::string m_implicit_value; + std::string m_default_value{}; + std::string m_implicit_value{}; }; template @@ -921,6 +949,7 @@ namespace cxxopts public: using abstract_value::abstract_value; + CXXOPTS_NODISCARD std::shared_ptr clone() const { @@ -996,6 +1025,7 @@ namespace cxxopts , m_value(std::move(val)) , m_count(0) { + m_hash = std::hash{}(m_long + m_short); } OptionDetails(const OptionDetails& rhs) @@ -1007,40 +1037,54 @@ namespace cxxopts OptionDetails(OptionDetails&& rhs) = default; + CXXOPTS_NODISCARD const String& description() const { return m_desc; } - const Value& value() const { + CXXOPTS_NODISCARD + const Value& + value() const { return *m_value; } + CXXOPTS_NODISCARD std::shared_ptr make_storage() const { return m_value->clone(); } + CXXOPTS_NODISCARD const std::string& short_name() const { return m_short; } + CXXOPTS_NODISCARD const std::string& long_name() const { return m_long; } + size_t + hash() const + { + return m_hash; + } + private: - std::string m_short; - std::string m_long; - String m_desc; - std::shared_ptr m_value; + std::string m_short{}; + std::string m_long{}; + String m_desc{}; + std::shared_ptr m_value{}; int m_count; + + size_t m_hash{}; }; struct HelpOptionDetails @@ -1059,9 +1103,9 @@ namespace cxxopts struct HelpGroupDetails { - std::string name; - std::string description; - std::vector options; + std::string name{}; + std::string description{}; + std::vector options{}; }; class OptionValue @@ -1077,6 +1121,7 @@ namespace cxxopts ensure_value(details); ++m_count; m_value->parse(text); + m_long_name = &details->long_name(); } void @@ -1084,9 +1129,11 @@ namespace cxxopts { ensure_value(details); m_default = true; + m_long_name = &details->long_name(); m_value->parse(); } + CXXOPTS_NODISCARD size_t count() const noexcept { @@ -1094,6 +1141,7 @@ namespace cxxopts } // TODO: maybe default options should count towards the number of arguments + CXXOPTS_NODISCARD bool has_default() const noexcept { @@ -1105,7 +1153,8 @@ namespace cxxopts as() const { if (m_value == nullptr) { - throw_or_mimic("No value"); + throw_or_mimic( + m_long_name == nullptr ? "" : *m_long_name); } #ifdef CXXOPTS_NO_RTTI @@ -1125,7 +1174,11 @@ namespace cxxopts } } - std::shared_ptr m_value; + + const std::string* m_long_name = nullptr; + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, + // where the key has the string we point to. + std::shared_ptr m_value{}; size_t m_count = 0; bool m_default = false; }; @@ -1139,15 +1192,15 @@ namespace cxxopts { } - const - std::string& + CXXOPTS_NODISCARD + const std::string& key() const { return m_key; } - const - std::string& + CXXOPTS_NODISCARD + const std::string& value() const { return m_value; @@ -1167,45 +1220,65 @@ namespace cxxopts std::string m_value; }; + using ParsedHashMap = std::unordered_map; + using NameHashMap = std::unordered_map; + class ParseResult { public: - ParseResult( - std::shared_ptr< - std::unordered_map> - >, - std::vector, - bool allow_unrecognised, - int&, char**&); + ParseResult() {} + + ParseResult(const ParseResult&) = default; + + ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector sequential, std::vector&& unmatched_args) + : m_keys(std::move(keys)) + , m_values(std::move(values)) + , m_sequential(std::move(sequential)) + , m_unmatched(std::move(unmatched_args)) + { + } + + ParseResult& operator=(ParseResult&&) = default; + ParseResult& operator=(const ParseResult&) = default; size_t count(const std::string& o) const { - auto iter = m_options->find(o); - if (iter == m_options->end()) + auto iter = m_keys.find(o); + if (iter == m_keys.end()) { return 0; } - auto riter = m_results.find(iter->second); + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + return 0; + } - return riter->second.count(); + return viter->second.count(); } const OptionValue& operator[](const std::string& option) const { - auto iter = m_options->find(option); + auto iter = m_keys.find(option); - if (iter == m_options->end()) + if (iter == m_keys.end()) { throw_or_mimic(option); } - auto riter = m_results.find(iter->second); + auto viter = m_values.find(iter->second); - return riter->second; + if (viter == m_values.end()) + { + throw_or_mimic(option); + } + + return viter->second; } const std::vector& @@ -1214,49 +1287,17 @@ namespace cxxopts return m_sequential; } - private: - - void - parse(int& argc, char**& argv); - - void - add_to_option(const std::string& option, const std::string& arg); - - bool - consume_positional(const std::string& a); - - void - parse_option - ( - const std::shared_ptr& value, - const std::string& name, - const std::string& arg = "" - ); - - void - parse_default(const std::shared_ptr& details); - - void - checked_parse_arg - ( - int argc, - char* argv[], - int& current, - const std::shared_ptr& value, - const std::string& name - ); - - const std::shared_ptr< - std::unordered_map> - > m_options; - std::vector m_positional; - std::vector::iterator m_next_positional; - std::unordered_set m_positional_set; - std::unordered_map, OptionValue> m_results; - - bool m_allow_unrecognised; + const std::vector& + unmatched() const + { + return m_unmatched; + } - std::vector m_sequential; + private: + NameHashMap m_keys{}; + ParsedHashMap m_values{}; + std::vector m_sequential{}; + std::vector m_unmatched{}; }; struct Option @@ -1281,9 +1322,66 @@ namespace cxxopts std::string arg_help_; }; + using OptionMap = std::unordered_map>; + using PositionalList = std::vector; + using PositionalListIterator = PositionalList::const_iterator; + + class OptionParser + { + public: + OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised) + : m_options(options) + , m_positional(positional) + , m_allow_unrecognised(allow_unrecognised) + { + } + + ParseResult + parse(int argc, const char* const* argv); + + bool + consume_positional(const std::string& a, PositionalListIterator& next); + + void + checked_parse_arg + ( + int argc, + const char* const* argv, + int& current, + const std::shared_ptr& value, + const std::string& name + ); + + void + add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg); + + void + parse_option + ( + const std::shared_ptr& value, + const std::string& name, + const std::string& arg = "" + ); + + void + parse_default(const std::shared_ptr& details); + + private: + + void finalise_aliases(); + + const OptionMap& m_options; + const PositionalList& m_positional; + + std::vector m_sequential{}; + bool m_allow_unrecognised; + + ParsedHashMap m_parsed{}; + NameHashMap m_keys{}; + }; + class Options { - using OptionMap = std::unordered_map>; public: explicit Options(std::string program, std::string help_string = "") @@ -1294,7 +1392,6 @@ namespace cxxopts , m_show_positional(false) , m_allow_unrecognised(false) , m_options(std::make_shared()) - , m_next_positional(m_positional.end()) { } @@ -1327,7 +1424,7 @@ namespace cxxopts } ParseResult - parse(int& argc, char**& argv); + parse(int argc, const char* const* argv); OptionAdder add_options(std::string group = ""); @@ -1404,20 +1501,22 @@ namespace cxxopts void generate_all_groups_help(String& result) const; - std::string m_program; - String m_help_string; - std::string m_custom_help; - std::string m_positional_help; + std::string m_program{}; + String m_help_string{}; + std::string m_custom_help{}; + std::string m_positional_help{}; bool m_show_positional; bool m_allow_unrecognised; std::shared_ptr m_options; - std::vector m_positional; - std::vector::iterator m_next_positional; - std::unordered_set m_positional_set; + std::vector m_positional{}; + std::unordered_set m_positional_set{}; //mapping from groups to help options - std::map m_help; + std::map m_help{}; + + std::list m_option_list{}; + std::unordered_map m_option_map{}; }; class OptionAdder @@ -1579,24 +1678,6 @@ namespace cxxopts } // namespace inline -ParseResult::ParseResult -( - std::shared_ptr< - std::unordered_map> - > options, - std::vector positional, - bool allow_unrecognised, - int& argc, char**& argv -) -: m_options(std::move(options)) -, m_positional(std::move(positional)) -, m_next_positional(m_positional.begin()) -, m_allow_unrecognised(allow_unrecognised) -{ - parse(argc, argv); -} - -inline void Options::add_options ( @@ -1675,21 +1756,24 @@ OptionAdder::operator() inline void -ParseResult::parse_default(const std::shared_ptr& details) +OptionParser::parse_default(const std::shared_ptr& details) { - m_results[details].parse_default(details); + // TODO: remove the duplicate code here + auto& store = m_parsed[details->hash()]; + store.parse_default(details); } inline void -ParseResult::parse_option +OptionParser::parse_option ( const std::shared_ptr& value, const std::string& /*name*/, const std::string& arg ) { - auto& result = m_results[value]; + auto hash = value->hash(); + auto& result = m_parsed[hash]; result.parse(value, arg); m_sequential.emplace_back(value->long_name(), arg); @@ -1697,10 +1781,10 @@ ParseResult::parse_option inline void -ParseResult::checked_parse_arg +OptionParser::checked_parse_arg ( int argc, - char* argv[], + const char* const* argv, int& current, const std::shared_ptr& value, const std::string& name @@ -1733,43 +1817,36 @@ ParseResult::checked_parse_arg inline void -ParseResult::add_to_option(const std::string& option, const std::string& arg) +OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg) { - auto iter = m_options->find(option); - - if (iter == m_options->end()) - { - throw_or_mimic(option); - } - parse_option(iter->second, option, arg); } inline bool -ParseResult::consume_positional(const std::string& a) +OptionParser::consume_positional(const std::string& a, PositionalListIterator& next) { - while (m_next_positional != m_positional.end()) + while (next != m_positional.end()) { - auto iter = m_options->find(*m_next_positional); - if (iter != m_options->end()) + auto iter = m_options.find(*next); + if (iter != m_options.end()) { - auto& result = m_results[iter->second]; + auto& result = m_parsed[iter->second->hash()]; if (!iter->second->value().is_container()) { if (result.count() == 0) { - add_to_option(*m_next_positional, a); - ++m_next_positional; + add_to_option(iter, *next, a); + ++next; return true; } - ++m_next_positional; + ++next; continue; } - add_to_option(*m_next_positional, a); + add_to_option(iter, *next, a); return true; } - throw_or_mimic(*m_next_positional); + throw_or_mimic(*next); } return false; @@ -1787,7 +1864,6 @@ void Options::parse_positional(std::vector options) { m_positional = std::move(options); - m_next_positional = m_positional.begin(); m_positional_set.insert(m_positional.begin(), m_positional.end()); } @@ -1801,21 +1877,21 @@ Options::parse_positional(std::initializer_list options) inline ParseResult -Options::parse(int& argc, char**& argv) +Options::parse(int argc, const char* const* argv) { - ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); - return result; + OptionParser parser(*m_options, m_positional, m_allow_unrecognised); + + return parser.parse(argc, argv); } -inline -void -ParseResult::parse(int& argc, char**& argv) +inline ParseResult +OptionParser::parse(int argc, const char* const* argv) { int current = 1; - - int nextKeep = 1; - bool consume_remaining = false; + PositionalListIterator next_positional = m_positional.begin(); + + std::vector unmatched; while (current != argc) { @@ -1842,13 +1918,12 @@ ParseResult::parse(int& argc, char**& argv) //if true is returned here then it was consumed, otherwise it is //ignored - if (consume_positional(argv[current])) + if (consume_positional(argv[current], next_positional)) { } else { - argv[nextKeep] = argv[current]; - ++nextKeep; + unmatched.push_back(argv[current]); } //if we return from here then it was parsed successfully, so continue } @@ -1862,9 +1937,9 @@ ParseResult::parse(int& argc, char**& argv) for (std::size_t i = 0; i != s.size(); ++i) { std::string name(1, s[i]); - auto iter = m_options->find(name); + auto iter = m_options.find(name); - if (iter == m_options->end()) + if (iter == m_options.end()) { if (m_allow_unrecognised) { @@ -1896,15 +1971,14 @@ ParseResult::parse(int& argc, char**& argv) { const std::string& name = result[1]; - auto iter = m_options->find(name); + auto iter = m_options.find(name); - if (iter == m_options->end()) + if (iter == m_options.end()) { if (m_allow_unrecognised) { // keep unrecognised options in argument list, skip to next argument - argv[nextKeep] = argv[current]; - ++nextKeep; + unmatched.push_back(argv[current]); ++current; continue; } @@ -1933,12 +2007,12 @@ ParseResult::parse(int& argc, char**& argv) ++current; } - for (auto& opt : *m_options) + for (auto& opt : m_options) { auto& detail = opt.second; const auto& value = detail->value(); - auto& store = m_results[detail]; + auto& store = m_parsed[detail->hash()]; if(value.has_default() && !store.count() && !store.has_default()){ parse_default(detail); @@ -1949,7 +2023,7 @@ ParseResult::parse(int& argc, char**& argv) { while (current < argc) { - if (!consume_positional(argv[current])) { + if (!consume_positional(argv[current], next_positional)) { break; } ++current; @@ -1957,14 +2031,30 @@ ParseResult::parse(int& argc, char**& argv) //adjust argv for any that couldn't be swallowed while (current != argc) { - argv[nextKeep] = argv[current]; - ++nextKeep; + unmatched.push_back(argv[current]); ++current; } } - argc = nextKeep; + finalise_aliases(); + ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(unmatched)); + return parsed; +} + +inline +void +OptionParser::finalise_aliases() +{ + for (auto& option: m_options) + { + auto& detail = *option.second; + auto hash = detail.hash(); + m_keys[detail.short_name()] = hash; + m_keys[detail.long_name()] = hash; + + m_parsed.emplace(hash, OptionValue()); + } } inline @@ -2003,6 +2093,11 @@ Options::add_option add_one_option(l, option); } + m_option_list.push_front(*option.get()); + auto iter = m_option_list.begin(); + m_option_map[s] = iter; + m_option_map[l] = iter; + //add the help details auto& options = m_help[group];