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";
73 template<
typename Target,
typename Source,
bool Same>
76 static Target
cast(
const Source &arg) {
79 if (!(ss << arg && ss >> ret && ss.eof())) {
87 template<
typename Target,
typename Source>
90 static Target
cast(
const Source &arg) {
95 template<
typename Source>
98 static std::string
cast(
const Source &arg) {
99 std::ostringstream ss;
105 template<
typename Target>
108 static Target
cast(
const std::string &arg) {
110 std::istringstream ss(arg);
111 if (!(ss >> ret && ss.eof())) {
118 template<
typename T1,
typename T2>
128 template<
typename Target,
typename Source>
133 static 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());
165 return detail::lexical_cast<std::string>(def);
169 inline std::string readable_typename<std::string>() {
173 #ifndef HALIDE_ENABLE_RTTI
189 #ifdef HALIDE_WITH_EXCEPTIONS
190 class cmdline_error :
public std::exception {
192 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";
216 return detail::lexical_cast<T>(str);
223 : low(low), high(high) {
227 if (!(ret >= low && ret <= high)) {
246 if (std::find(alt.begin(), alt.end(), ret) == alt.end()) {
380 for (std::map<std::string, option_base *>::iterator p = options.begin();
381 p != options.end(); p++) {
386 void add(
const std::string &name,
388 const std::string &desc =
"") {
389 if (options.count(name)) {
392 options[name] =
new option_without_value(name, short_name, desc);
393 ordered.push_back(options[name]);
397 void add(
const std::string &name,
399 const std::string &desc =
"",
405 template<
class T,
class F>
406 void add(
const std::string &name,
408 const std::string &desc =
"",
412 if (options.count(name)) {
415 options[name] =
new option_with_value_with_reader<T, F>(name, short_name, need, def, desc, reader);
416 ordered.push_back(options[name]);
427 bool exist(
const std::string &name)
const {
428 if (options.count(name) == 0) {
431 return options.find(name)->second->has_set();
435 const T &
get(
const std::string &name)
const {
436 if (options.count(name) == 0) {
439 #ifndef HALIDE_ENABLE_RTTI
440 const option_with_value<T> *p =
reinterpret_cast<const option_with_value<T> *
>(options.find(name)->second);
443 const option_with_value<T> *p =
dynamic_cast<const option_with_value<T> *
>(options.find(name)->second);
451 const std::vector<std::string> &
rest()
const {
455 bool parse(
const std::string &arg) {
456 std::vector<std::string> args;
459 bool in_quote =
false;
460 for (std::string::size_type i = 0; i < arg.length(); i++) {
461 if (arg[i] ==
'\"') {
462 in_quote = !in_quote;
466 if (arg[i] ==
' ' && !in_quote) {
472 if (arg[i] ==
'\\') {
474 if (i >= arg.length()) {
475 errors.emplace_back(
"unexpected occurrence of '\\' at end of string");
484 errors.emplace_back(
"quote is not closed");
488 if (
buf.length() > 0) {
492 for (
size_t i = 0; i < args.size(); i++) {
493 std::cout <<
"\"" << args[i] <<
"\"" << std::endl;
499 bool parse(
const std::vector<std::string> &args) {
500 int argc =
static_cast<int>(args.size());
501 std::vector<const char *> argv(argc);
503 for (
int i = 0; i < argc; i++) {
504 argv[i] = args[i].c_str();
507 return parse(argc, &argv[0]);
510 bool parse(
int argc,
const char *
const argv[]) {
515 errors.emplace_back(
"argument number must be longer than 0");
518 if (prog_name.empty()) {
522 std::map<char, std::string> lookup;
523 for (std::map<std::string, option_base *>::iterator p = options.begin();
524 p != options.end(); p++) {
525 if (p->first.length() == 0) {
528 char initial = p->second->short_name();
530 if (lookup.count(initial) > 0) {
531 lookup[initial] =
"";
532 errors.push_back(std::string(
"short option '") + initial +
"' is ambiguous");
535 lookup[initial] = p->first;
540 for (
int i = 1; i < argc; i++) {
541 if (
strncmp(argv[i],
"--", 2) == 0) {
542 const char *p =
strchr(argv[i] + 2,
'=');
544 std::string name(argv[i] + 2, p);
545 std::string val(p + 1);
546 set_option(name, val);
548 std::string name(argv[i] + 2);
549 if (options.count(name) == 0) {
550 errors.push_back(
"undefined option: --" + name);
553 if (options[name]->has_value()) {
555 errors.push_back(
"option needs value: --" + name);
559 set_option(name, argv[i]);
565 }
else if (
strncmp(argv[i],
"-", 1) == 0) {
569 char last = argv[i][1];
570 for (
int j = 2; argv[i][j]; j++) {
572 if (lookup.count(argv[i][j - 1]) == 0) {
573 errors.push_back(std::string(
"undefined short option: -") + argv[i][j - 1]);
576 if (lookup[argv[i][j - 1]].empty()) {
577 errors.push_back(std::string(
"ambiguous short option: -") + argv[i][j - 1]);
580 set_option(lookup[argv[i][j - 1]]);
583 if (lookup.count(last) == 0) {
584 errors.push_back(std::string(
"undefined short option: -") + last);
587 if (lookup[last].empty()) {
588 errors.push_back(std::string(
"ambiguous short option: -") + last);
592 if (i + 1 < argc && options[lookup[last]]->has_value()) {
593 set_option(lookup[last], argv[i + 1]);
596 set_option(lookup[last]);
599 others.emplace_back(argv[i]);
603 for (std::map<std::string, option_base *>::iterator p = options.begin();
604 p != options.end(); p++) {
605 if (!p->second->valid()) {
606 errors.push_back(
"need option: --" + std::string(p->first));
610 return errors.empty();
614 if (!options.count(
"help")) {
615 add(
"help",
'?',
"print this message");
617 check(0,
parse(arg));
621 if (!options.count(
"help")) {
622 add(
"help",
'?',
"print this message");
624 check(args.size(),
parse(args));
628 if (!options.count(
"help")) {
629 add(
"help",
'?',
"print this message");
631 check(argc,
parse(argc, argv));
635 return !errors.empty() ? errors[0] :
"";
639 std::ostringstream oss;
640 for (
size_t i = 0; i < errors.size(); i++) {
641 oss << errors[i] << std::endl;
647 std::ostringstream oss;
648 oss <<
"usage: " << prog_name <<
" ";
649 for (
size_t i = 0; i < ordered.size(); i++) {
650 if (ordered[i]->must()) {
651 oss << ordered[i]->short_description() <<
" ";
655 oss <<
"[options] ... " << ftr << std::endl;
656 oss <<
"options:" << std::endl;
658 size_t max_width = 0;
659 for (
size_t i = 0; i < ordered.size(); i++) {
660 max_width =
std::max(max_width, ordered[i]->name().length());
662 for (
size_t i = 0; i < ordered.size(); i++) {
663 if (ordered[i]->short_name()) {
664 oss <<
" -" << ordered[i]->short_name() <<
", ";
669 oss <<
"--" << ordered[i]->name();
670 for (
size_t j = ordered[i]->name().length(); j < max_width + 4; j++) {
673 oss << ordered[i]->description() << std::endl;
679 void check(
int argc,
bool ok) {
680 if ((argc == 1 && !ok) ||
exist(
"help")) {
681 std::cerr <<
usage();
686 std::cerr <<
error() << std::endl
692 void set_option(
const std::string &name) {
693 if (options.count(name) == 0) {
694 errors.push_back(
"undefined option: --" + name);
697 if (!options[name]->set()) {
698 errors.push_back(
"option needs value: --" + name);
703 void set_option(
const std::string &name,
const std::string &value) {
704 if (options.count(name) == 0) {
705 errors.push_back(
"undefined option: --" + name);
708 if (!options[name]->set(value)) {
709 errors.push_back(
"option value is invalid: --" + name +
"=" + value);
716 virtual ~option_base() =
default;
718 virtual bool has_value()
const = 0;
719 virtual bool set() = 0;
720 virtual bool set(
const std::string &value) = 0;
721 virtual bool has_set()
const = 0;
722 virtual bool valid()
const = 0;
723 virtual bool must()
const = 0;
725 virtual const std::string &name()
const = 0;
726 virtual char short_name()
const = 0;
727 virtual const std::string &description()
const = 0;
728 virtual std::string short_description()
const = 0;
731 class option_without_value :
public option_base {
733 option_without_value(
const std::string &name,
735 const std::string &desc)
736 : nam(name), snam(short_name), desc(desc), has(false) {
738 ~option_without_value()
override =
default;
740 bool has_value()
const override {
744 bool set()
override {
749 bool set(
const std::string &)
override {
753 bool has_set()
const override {
757 bool valid()
const override {
761 bool must()
const override {
765 const std::string &name()
const override {
769 char short_name()
const override {
773 const std::string &description()
const override {
777 std::string short_description()
const override {
789 class option_with_value :
public option_base {
791 option_with_value(
const std::string &name,
795 const std::string &desc)
796 : nam(name), snam(short_name), need(need), has(false), def(def), actual(def) {
797 this->desc = full_description(desc);
799 ~option_with_value()
override =
default;
801 const T &
get()
const {
805 bool has_value()
const override {
809 bool set()
override {
813 bool set(
const std::string &value)
override {
814 #ifdef HALIDE_WITH_EXCEPTIONS
816 actual = read(value);
818 }
catch (
const std::exception &e) {
819 std::cout <<
"Exception was caught: " << e.what() << std::endl;
824 actual = read(value);
830 bool has_set()
const override {
834 bool valid()
const override {
841 bool must()
const override {
845 const std::string &name()
const override {
849 char short_name()
const override {
853 const std::string &description()
const override {
857 std::string short_description()
const override {
858 return "--" + nam +
"=" + detail::readable_typename<T>();
862 std::string full_description(
const std::string &desc) {
863 return desc +
" (" + detail::readable_typename<T>() +
864 (need ?
"" :
" [=" + detail::default_value<T>(def) +
"]") +
")";
867 virtual T read(
const std::string &s) = 0;
879 template<
class T,
class F>
880 class option_with_value_with_reader :
public option_with_value<T> {
882 option_with_value_with_reader(
const std::string &name,
886 const std::string &desc,
888 : option_with_value<T>(name, short_name, need, def, desc), reader(reader) {
892 T read(
const std::string &s)
override {
899 std::map<std::string, option_base *> options;
900 std::vector<option_base *> ordered;
903 std::string prog_name;
904 std::vector<std::string> others;
906 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 std::vector< std::string > & rest() const
bool parse(const std::vector< std::string > &args)
const T & get(const std::string &name) 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)
HALIDE_ALWAYS_INLINE auto cast(halide_type_t t, A &&a) noexcept -> CastOp< decltype(pattern_arg(a))>
Expr max(const FuncRef &a, const FuncRef &b)
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 >()
range_reader< T > range(const T &low, const T &high)
void throw_cmdline_error(const std::string &s)
oneof_reader< T > oneof(T a1)
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