45#if defined(_MSC_VER) && !defined(NOMINMAX)
53#pragma warning(disable : 4091)
55#pragma comment(lib, "dbghelp.lib")
62#ifdef HALIDE_WITH_EXCEPTIONS
64 throw std::bad_cast();
68 std::cerr <<
"bad cast\n";
73template<
typename Target,
typename Source,
bool Same>
76 static Target
cast(
const Source &arg) {
79 if (!(ss << arg && ss >> ret && ss.eof())) {
87template<
typename Target,
typename Source>
90 static Target
cast(
const Source &arg) {
95template<
typename Source>
98 static std::string
cast(
const Source &arg) {
99 std::ostringstream ss;
105template<
typename Target>
108 static Target
cast(
const std::string &arg) {
110 std::istringstream ss(arg);
111 if (!(ss >> ret && ss.eof())) {
118template<
typename T1,
typename T2>
128template<
typename Target,
typename Source>
133static inline std::string demangle(
const std::string &name) {
136 char *p = abi::__cxa_demangle(name.c_str(),
nullptr,
nullptr, &status);
141 char demangled_name[8192];
142 if (UnDecorateSymbolName(name.c_str(), demangled_name,
sizeof(demangled_name),
144 std::string ret(demangled_name);
147 DWORD error = GetLastError();
148 std::cout <<
"UnDecorateSymbolName error: " << error << std::endl;
156#ifndef HALIDE_ENABLE_RTTI
157 return "unrecognized type";
159 return demangle(
typeid(T).name());
173#ifndef HALIDE_ENABLE_RTTI
189#ifdef HALIDE_WITH_EXCEPTIONS
190class cmdline_error :
public std::exception {
192 explicit cmdline_error(
const std::string &msg)
195 ~cmdline_error() throw() override = default;
196 const
char *what() const throw()
override {
204 throw cmdline::cmdline_error(s);
208 std::cerr <<
"error: " << s <<
"\n";
223 : low(low), high(high) {
227 if (!(ret >= low && ret <= high)) {
246 if (std::find(alt.begin(), alt.end(), ret) == alt.end()) {
380 for (
auto &option : options) {
381 delete option.second;
385 void add(
const std::string &name,
387 const std::string &desc =
"") {
388 if (options.count(name)) {
391 options[name] =
new option_without_value(name, short_name, desc);
392 ordered.push_back(options[name]);
396 void add(
const std::string &name,
398 const std::string &desc =
"",
404 template<
class T,
class F>
405 void add(
const std::string &name,
407 const std::string &desc =
"",
411 if (options.count(name)) {
414 options[name] =
new option_with_value_with_reader<T, F>(name, short_name, need, def, desc, reader);
415 ordered.push_back(options[name]);
426 bool exist(
const std::string &name)
const {
427 if (options.count(name) == 0) {
430 return options.find(name)->second->has_set();
434 const T &
get(
const std::string &name)
const {
435 if (options.count(name) == 0) {
438#ifndef HALIDE_ENABLE_RTTI
439 const option_with_value<T> *p =
reinterpret_cast<const option_with_value<T> *
>(options.find(name)->second);
442 const option_with_value<T> *p =
dynamic_cast<const option_with_value<T> *
>(options.find(name)->second);
450 const std::vector<std::string> &
rest()
const {
454 bool parse(
const std::string &arg) {
455 std::vector<std::string> args;
458 bool in_quote =
false;
459 for (std::string::size_type i = 0; i < arg.length(); i++) {
460 if (arg[i] ==
'\"') {
461 in_quote = !in_quote;
465 if (arg[i] ==
' ' && !in_quote) {
471 if (arg[i] ==
'\\') {
473 if (i >= arg.length()) {
474 errors.emplace_back(
"unexpected occurrence of '\\' at end of string");
483 errors.emplace_back(
"quote is not closed");
491 for (
auto &arg : args) {
492 std::cout <<
"\"" << arg <<
"\"\n";
498 bool parse(
const std::vector<std::string> &args) {
499 int argc =
static_cast<int>(args.size());
500 std::vector<const char *> argv(argc);
502 for (
int i = 0; i < argc; i++) {
503 argv[i] = args[i].c_str();
506 return parse(argc, &argv[0]);
509 bool parse(
int argc,
const char *
const argv[]) {
514 errors.emplace_back(
"argument number must be longer than 0");
517 if (prog_name.empty()) {
521 std::map<char, std::string> lookup;
522 for (
auto &option : options) {
523 if (option.first.empty()) {
526 char initial = option.second->short_name();
528 if (lookup.count(initial) > 0) {
529 lookup[initial] =
"";
530 errors.push_back(std::string(
"short option '") + initial +
"' is ambiguous");
533 lookup[initial] = option.first;
538 for (
int i = 1; i < argc; i++) {
539 if (
strncmp(argv[i],
"--", 2) == 0) {
540 const char *p =
strchr(argv[i] + 2,
'=');
542 std::string name(argv[i] + 2, p);
543 std::string val(p + 1);
544 set_option(name, val);
546 std::string name(argv[i] + 2);
547 if (options.count(name) == 0) {
548 errors.push_back(
"undefined option: --" + name);
551 if (options[name]->has_value()) {
553 errors.push_back(
"option needs value: --" + name);
557 set_option(name, argv[i]);
563 }
else if (
strncmp(argv[i],
"-", 1) == 0) {
567 char last = argv[i][1];
568 for (
int j = 2; argv[i][j]; j++) {
570 if (lookup.count(argv[i][j - 1]) == 0) {
571 errors.push_back(std::string(
"undefined short option: -") + argv[i][j - 1]);
574 if (lookup[argv[i][j - 1]].empty()) {
575 errors.push_back(std::string(
"ambiguous short option: -") + argv[i][j - 1]);
578 set_option(lookup[argv[i][j - 1]]);
581 if (lookup.count(last) == 0) {
582 errors.push_back(std::string(
"undefined short option: -") + last);
585 if (lookup[last].empty()) {
586 errors.push_back(std::string(
"ambiguous short option: -") + last);
590 if (i + 1 < argc && options[lookup[last]]->has_value()) {
591 set_option(lookup[last], argv[i + 1]);
594 set_option(lookup[last]);
597 others.emplace_back(argv[i]);
601 for (
auto &option : options) {
602 if (!option.second->valid()) {
603 errors.push_back(
"need option: --" + std::string(option.first));
607 return errors.empty();
611 if (!options.count(
"help")) {
612 add(
"help",
'?',
"print this message");
614 check(0,
parse(arg));
618 if (!options.count(
"help")) {
619 add(
"help",
'?',
"print this message");
621 check(args.size(),
parse(args));
625 if (!options.count(
"help")) {
626 add(
"help",
'?',
"print this message");
628 check(argc,
parse(argc, argv));
632 return !errors.empty() ? errors[0] :
"";
636 std::ostringstream oss;
637 for (
const auto &
error : errors) {
638 oss <<
error <<
"\n";
644 std::ostringstream oss;
645 oss <<
"usage: " << prog_name <<
" ";
646 for (
const auto &o : ordered) {
648 oss << o->short_description() <<
" ";
652 oss <<
"[options] ... " << ftr <<
"\n";
655 size_t max_width = 0;
656 for (
const auto &o : ordered) {
657 max_width = std::max(max_width, o->name().length());
659 for (
const auto &o : ordered) {
660 if (o->short_name()) {
661 oss <<
" -" << o->short_name() <<
", ";
666 oss <<
"--" << o->name();
667 for (
size_t j = o->name().length(); j < max_width + 4; j++) {
670 oss << o->description() <<
"\n";
676 void check(
int argc,
bool ok) {
677 if ((argc == 1 && !ok) ||
exist(
"help")) {
678 std::cerr <<
usage();
683 std::cerr <<
error() <<
"\n"
689 void set_option(
const std::string &name) {
690 if (options.count(name) == 0) {
691 errors.push_back(
"undefined option: --" + name);
694 if (!options[name]->set()) {
695 errors.push_back(
"option needs value: --" + name);
700 void set_option(
const std::string &name,
const std::string &value) {
701 if (options.count(name) == 0) {
702 errors.push_back(
"undefined option: --" + name);
705 if (!options[name]->set(value)) {
706 errors.push_back(
"option value is invalid: --" + name +
"=" + value);
713 virtual ~option_base() =
default;
715 virtual bool has_value()
const = 0;
716 virtual bool set() = 0;
717 virtual bool set(
const std::string &value) = 0;
718 virtual bool has_set()
const = 0;
719 virtual bool valid()
const = 0;
720 virtual bool must()
const = 0;
722 virtual const std::string &name()
const = 0;
723 virtual char short_name()
const = 0;
724 virtual const std::string &description()
const = 0;
725 virtual std::string short_description()
const = 0;
728 class option_without_value :
public option_base {
730 option_without_value(
const std::string &name,
732 const std::string &desc)
733 : nam(name), snam(short_name), desc(desc) {
735 ~option_without_value()
override =
default;
737 bool has_value()
const override {
741 bool set()
override {
746 bool set(
const std::string &)
override {
750 bool has_set()
const override {
754 bool valid()
const override {
758 bool must()
const override {
762 const std::string &name()
const override {
766 char short_name()
const override {
770 const std::string &description()
const override {
774 std::string short_description()
const override {
786 class option_with_value :
public option_base {
788 option_with_value(
const std::string &name,
792 const std::string &desc)
793 : nam(name), snam(short_name), need(need), def(def), actual(def) {
794 this->desc = full_description(desc);
796 ~option_with_value()
override =
default;
798 const T &get()
const {
802 bool has_value()
const override {
806 bool set()
override {
810 bool set(
const std::string &value)
override {
811#ifdef HALIDE_WITH_EXCEPTIONS
813 actual = read(value);
815 }
catch (
const std::exception &e) {
816 std::cout <<
"Exception was caught: " << e.what() <<
"\n";
821 actual = read(value);
827 bool has_set()
const override {
831 bool valid()
const override {
838 bool must()
const override {
842 const std::string &name()
const override {
846 char short_name()
const override {
850 const std::string &description()
const override {
854 std::string short_description()
const override {
859 std::string full_description(
const std::string &desc) {
864 virtual T read(
const std::string &s) = 0;
876 template<
class T,
class F>
877 class option_with_value_with_reader :
public option_with_value<T> {
879 option_with_value_with_reader(
const std::string &name,
883 const std::string &desc,
885 : option_with_value<T>(name, short_name, need, def, desc), reader(reader) {
889 T read(
const std::string &s)
override {
896 std::map<std::string, option_base *> options;
897 std::vector<option_base *> ordered;
900 std::string prog_name;
901 std::vector<std::string> others;
903 std::vector<std::string> errors;
static Target cast(const Source &arg)
static Target cast(const std::string &arg)
static std::string cast(const Source &arg)
static Target cast(const Source &arg)
void footer(const std::string &f)
std::string error_full() const
void parse_check(const std::vector< std::string > &args)
void add(const std::string &name, char short_name=0, const std::string &desc="")
std::string usage() const
const T & get(const std::string &name) const
bool parse(const std::vector< std::string > &args)
const std::vector< std::string > & rest() const
bool parse(int argc, const char *const argv[])
std::string error() const
void parse_check(int argc, char *argv[])
void add(const std::string &name, char short_name=0, const std::string &desc="", bool need=true, const T def=T(), F reader=F())
bool parse(const std::string &arg)
bool exist(const std::string &name) const
void parse_check(const std::string &arg)
void add(const std::string &name, char short_name=0, const std::string &desc="", bool need=true, const T def=T())
void set_program_name(const std::string &name)
std::string default_value(T def)
std::string readable_typename< int >()
Target lexical_cast(const Source &arg)
std::string readable_typename()
std::string readable_typename< bool >()
std::string readable_typename< std::string >()
oneof_reader< T > oneof(T a1)
range_reader< T > range(const T &low, const T &high)
void throw_cmdline_error(const std::string &s)
const char * strchr(const char *s, int c)
int strncmp(const char *s, const char *t, size_t n)
T operator()(const std::string &str)
T operator()(const std::string &s)
range_reader(const T &low, const T &high)
T operator()(const std::string &s) const