ONE - On-device Neural Engine
Loading...
Searching...
No Matches
arser::Arser Class Reference

#include <arser.h>

Public Member Functions

 Arser (const std::string &program_description={})
 
Argumentadd_argument (const std::string &arg_name)
 
Argumentadd_argument (const std::vector< std::string > &arg_name_vec)
 
template<typename... Ts>
Argumentadd_argument (const std::string &arg_name, Ts... arg_names)
 
void validate_arguments (void)
 
void parse (int argc, char **argv)
 
bool operator[] (const std::string &arg_name)
 
template<typename T >
get_impl (const std::string &arg_name, T *)
 
template<typename T >
std::vector< T > get_impl (const std::string &arg_name, std::vector< T > *)
 
template<typename T >
std::vector< std::vector< T > > get_impl (const std::string &arg_name, std::vector< std::vector< T > > *)
 
template<typename T >
get (const std::string &arg_name)
 

Friends

std::ostream & operator<< (std::ostream &stream, const Arser &parser)
 

Detailed Description

Definition at line 329 of file arser.h.

Constructor & Destructor Documentation

◆ Arser()

arser::Arser::Arser ( const std::string &  program_description = {})
inlineexplicit

Definition at line 332 of file arser.h.

332 {})
333 : _program_description{program_description}
334 {
335 add_argument("-h", "--help").help("Show help message and exit").nargs(0);
336 }
Argument & nargs(uint32_t num)
Definition arser.h:189
Argument & help(std::string help_message)
Definition arser.h:254
Argument & add_argument(const std::string &arg_name)
Definition arser.h:338

Member Function Documentation

◆ add_argument() [1/3]

Argument & arser::Arser::add_argument ( const std::string &  arg_name)
inline

Definition at line 338 of file arser.h.

339 {
340 if (arg_name.at(0) != '-') /* positional */
341 {
342 _positional_arg_vec.emplace_back(arg_name);
343 _arg_map[arg_name] = &_positional_arg_vec.back();
344 }
345 else /* optional */
346 {
347 // The length of optional argument name must be 2 or more.
348 // And it shouldn't be hard to recognize. e.g. '-', '--'
349 if (arg_name.size() < 2)
350 {
351 throw std::runtime_error("Too short name. The length of argument name must be 2 or more.");
352 }
353 if (arg_name == "--")
354 {
355 throw std::runtime_error(
356 "Too short name. Option name must contain at least one character other than dash.");
357 }
358 _optional_arg_vec.emplace_back(arg_name);
359 _optional_arg_vec.back()._short_name = arg_name;
360 _arg_map[arg_name] = &_optional_arg_vec.back();
361 }
362 return *_arg_map[arg_name];
363 }

Referenced by add_argument().

◆ add_argument() [2/3]

template<typename... Ts>
Argument & arser::Arser::add_argument ( const std::string &  arg_name,
Ts...  arg_names 
)
inline

Definition at line 407 of file arser.h.

408 {
409 if (sizeof...(arg_names) == 0)
410 {
411 return add_argument(arg_name);
412 }
413 // sizeof...(arg_names) > 0
414 else
415 {
416 return add_argument(std::vector<std::string>{arg_name, arg_names...});
417 }
418 }

References add_argument().

◆ add_argument() [3/3]

Argument & arser::Arser::add_argument ( const std::vector< std::string > &  arg_name_vec)
inline

Definition at line 365 of file arser.h.

366 {
367 assert(arg_name_vec.size() >= 2);
368 std::string long_opt, short_opt;
369 // find long and short option
370 for (const auto &arg_name : arg_name_vec)
371 {
372 if (arg_name.at(0) != '-')
373 {
374 throw std::runtime_error("Invalid argument. "
375 "Positional argument cannot have short option.");
376 }
377 assert(arg_name.size() >= 2);
378 if (long_opt.empty() && arg_name.at(0) == '-' && arg_name.at(1) == '-')
379 {
380 long_opt = arg_name;
381 }
382 if (short_opt.empty() && arg_name.at(0) == '-' && arg_name.at(1) != '-')
383 {
384 short_opt = arg_name;
385 }
386 }
387 // If one of the two is empty, fill it with the non-empty one for pretty printing.
388 if (long_opt.empty())
389 {
390 assert(not short_opt.empty());
391 long_opt = short_opt;
392 }
393 if (short_opt.empty())
394 {
395 assert(not long_opt.empty());
396 short_opt = long_opt;
397 }
398
399 _optional_arg_vec.emplace_back(short_opt, long_opt, arg_name_vec);
400 for (const auto &arg_name : arg_name_vec)
401 {
402 _arg_map[arg_name] = &_optional_arg_vec.back();
403 }
404 return _optional_arg_vec.back();
405 }

◆ get()

template<typename T >
T arser::Arser::get ( const std::string &  arg_name)

Definition at line 747 of file arser.h.

748{
749 return get_impl(arg_name, static_cast<T *>(nullptr));
750}
T get_impl(const std::string &arg_name, T *)
Definition arser.h:642

References get_impl().

◆ get_impl() [1/3]

template<typename T >
std::vector< std::vector< T > > arser::Arser::get_impl ( const std::string &  arg_name,
std::vector< std::vector< T > > *   
)

Definition at line 714 of file arser.h.

716{
717 auto arg = _arg_map.find(arg_name);
718 if (arg == _arg_map.end())
719 throw std::runtime_error("Invalid argument. "
720 "There is no argument you are looking for: " +
721 arg_name);
722
723 if (not arg->second->_is_accumulated)
724 throw std::runtime_error("Type mismatch. "
725 "You called get using a type different from the one you specified: " +
726 arg_name);
727
728 if (arg->second->_type != TypeName<std::vector<T>>::Get())
729 throw std::runtime_error(
730 "Type mismatch. "
731 "You called get using a type different from the one you specified."
732 "Accumulated argument is returned as std::vector of the specified type: " +
733 arg_name);
734
735 std::vector<std::vector<T>> result;
736 for (auto values : arg->second->_accum_values)
737 {
738 std::vector<T> data;
739 std::transform(values.begin(), values.end(), std::back_inserter(data),
740 [](std::string str) -> T { return internal::lexical_cast<T>(str); });
741 result.emplace_back(data);
742 }
743
744 return result;
745}
result
Definition infer.py:103

◆ get_impl() [2/3]

template<typename T >
std::vector< T > arser::Arser::get_impl ( const std::string &  arg_name,
std::vector< T > *   
)

Definition at line 674 of file arser.h.

675{
676 auto arg = _arg_map.find(arg_name);
677 if (arg == _arg_map.end())
678 throw std::runtime_error("Invalid argument. "
679 "There is no argument you are looking for: " +
680 arg_name);
681
682 // Accumulated arguments with scalar type (e.g., STR)
683 if (arg->second->_is_accumulated)
684 {
685 if (arg->second->_type != TypeName<T>::Get())
686 throw std::runtime_error(
687 "Type mismatch. "
688 "You called get using a type different from the one you specified: " +
689 arg_name);
690
691 std::vector<T> data;
692 for (auto values : arg->second->_accum_values)
693 {
694 assert(values.size() == 1);
695 data.emplace_back(internal::lexical_cast<T>(values[0]));
696 }
697 return data;
698 }
699
700 if (arg->second->_type != TypeName<std::vector<T>>::Get())
701 throw std::runtime_error(
702 "Type mismatch. "
703 ". You called get using a type different from the one you specified: " +
704 arg_name);
705
706 std::vector<T> data;
707 std::transform(arg->second->_values.begin(), arg->second->_values.end(), std::back_inserter(data),
708 [](std::string str) -> T { return internal::lexical_cast<T>(str); });
709 return data;
710}
static const char * Get()
Definition arser.h:100

◆ get_impl() [3/3]

template<typename T >
T arser::Arser::get_impl ( const std::string &  arg_name,
T *   
)

Definition at line 642 of file arser.h.

643{
644 auto arg = _arg_map.find(arg_name);
645 if (arg == _arg_map.end())
646 throw std::runtime_error("Invalid argument. "
647 "There is no argument you are looking for: " +
648 arg_name);
649
650 if (arg->second->_is_accumulated)
651 throw std::runtime_error(
652 "Type mismatch. "
653 "You called get using a type different from the one you specified."
654 "Accumulated argument is returned as std::vector of the specified type: " +
655 arg_name);
656
657 if (arg->second->_type != TypeName<T>::Get())
658 throw std::runtime_error("Type mismatch. "
659 "You called get() method with a type different "
660 "from the one you specified. "
661 "Please check the type of what you specified in "
662 "add_argument() method: " +
663 arg_name);
664
665 if (arg->second->_values.size() == 0)
666 throw std::runtime_error("Wrong access. "
667 "You must make sure that the argument is given before accessing it. "
668 "You can do it by calling arser[\"" +
669 arg_name + "\"].");
670
671 return internal::lexical_cast<T>(arg->second->_values[0]);
672}

Referenced by get().

◆ operator[]()

bool arser::Arser::operator[] ( const std::string &  arg_name)
inline

Definition at line 521 of file arser.h.

522 {
523 auto arg = _arg_map.find(arg_name);
524 if (arg == _arg_map.end())
525 return false;
526
527 if (arg->second->_is_accumulated)
528 return arg->second->_accum_values.size() > 0 ? true : false;
529
530 return arg->second->_values.size() > 0 ? true : false;
531 }

◆ parse()

void arser::Arser::parse ( int  argc,
char **  argv 
)
inline

Definition at line 434 of file arser.h.

435 {
437 _program_name = argv[0];
438 _program_name.erase(0, _program_name.find_last_of("/\\") + 1);
439 if (argc >= 2)
440 {
441 if (!std::strcmp(argv[1], "--help") || !std::strcmp(argv[1], "-h"))
442 {
443 std::cout << *this;
444 std::exit(0);
445 }
446 else
447 {
448 for (const auto &arg : _arg_map)
449 {
450 const auto &func = arg.second->_func;
451 if (func && !std::strcmp(argv[1], arg.first.c_str()))
452 {
453 func();
454 std::exit(0);
455 }
456 }
457 }
458 }
459 /*
460 ** ./program_name [optional argument] [positional argument]
461 */
462 // get the number of positioanl argument
463 size_t parg_num = _positional_arg_vec.size();
464 // get the number of "required" optional argument
465 size_t required_oarg_num = 0;
466 for (auto arg : _optional_arg_vec)
467 {
468 if (arg._is_required)
469 required_oarg_num++;
470 }
471 // parse argument
472 for (int c = 1; c < argc;)
473 {
474 std::string arg_name{argv[c++]};
475 auto arg = _arg_map.find(arg_name);
476 // check whether arg is positional or not
477 if (arg == _arg_map.end())
478 {
479 if (parg_num)
480 {
481 auto it = _positional_arg_vec.begin();
482 std::advance(it, _positional_arg_vec.size() - parg_num);
483 (*it)._values.clear();
484 (*it)._values.emplace_back(arg_name);
485 parg_num--;
486 }
487 else
488 throw std::runtime_error("Invalid argument. "
489 "You've given more positional argument than necessary.");
490 }
491 else // optional argument
492 {
493 // check whether arg is required or not
494 if (arg->second->_is_required)
495 required_oarg_num--;
496 arg->second->_values.clear();
497 for (uint32_t n = 0; n < arg->second->_nargs; n++)
498 {
499 if (c >= argc)
500 throw std::runtime_error("Invalid argument. "
501 "You must have missed some argument.");
502 arg->second->_values.emplace_back(argv[c++]);
503 }
504 // accumulate values
505 if (arg->second->_is_accumulated)
506 {
507 arg->second->_accum_values.emplace_back(arg->second->_values);
508 }
509 if (arg->second->_nargs == 0)
510 {
511 // TODO std::boolalpha for true or false
512 arg->second->_values.emplace_back("1");
513 }
514 }
515 }
516 if (parg_num || required_oarg_num)
517 throw std::runtime_error("Invalid argument. "
518 "You must have missed some argument.");
519 }
void validate_arguments(void)
Definition arser.h:420

References validate_arguments().

◆ validate_arguments()

void arser::Arser::validate_arguments ( void  )
inline

Definition at line 420 of file arser.h.

421 {
422 // positional argument is always required.
423 for (const auto &arg : _positional_arg_vec)
424 {
425 if (arg._is_required)
426 {
427 throw std::runtime_error("Invalid arguments. Positional argument must always be required.");
428 }
429 }
430 // TODO accumulated arguments shouldn't be enabled to positional arguments.
431 // TODO accumulated arguments shouldn't be enabled to optional arguments whose `narg` == 0.
432 }

Referenced by parse().

Friends And Related Symbol Documentation

◆ operator<<

std::ostream & operator<< ( std::ostream &  stream,
const Arser parser 
)
friend

Definition at line 542 of file arser.h.

543 {
544 // print description
545 if (!parser._program_description.empty())
546 {
547 stream << "What " << parser._program_name << " does: " << parser._program_description
548 << "\n\n";
549 }
550 /*
551 ** print usage
552 */
553 auto print_usage_arg = [&](const arser::Argument &arg) {
554 stream << " ";
555 std::string arg_name = arser::internal::remove_dash(arg._long_name);
556 std::for_each(arg_name.begin(), arg_name.end(),
557 [&stream](const char &c) { stream << static_cast<char>(::toupper(c)); });
558 };
559 stream << "Usage: ./" << parser._program_name << " ";
560 // required optional argument
561 for (const auto &arg : parser._optional_arg_vec)
562 {
563 if (!arg._is_required)
564 continue;
565 stream << arg._short_name;
566 print_usage_arg(arg);
567 stream << " ";
568 }
569 // rest of the optional argument
570 for (const auto &arg : parser._optional_arg_vec)
571 {
572 if (arg._is_required)
573 continue;
574 stream << "[" << arg._short_name;
575 if (arg._nargs)
576 {
577 print_usage_arg(arg);
578 }
579 stream << "]"
580 << " ";
581 }
582 // positional arguement
583 for (const auto &arg : parser._positional_arg_vec)
584 {
585 stream << arg._long_name << " ";
586 }
587 stream << "\n\n";
588 /*
589 ** print argument list and its help message
590 */
591 // get the length of the longest argument
592 size_t length_of_longest_arg = 0;
593 for (const auto &arg : parser._positional_arg_vec)
594 {
595 length_of_longest_arg = std::max(length_of_longest_arg,
597 }
598 for (const auto &arg : parser._optional_arg_vec)
599 {
600 length_of_longest_arg = std::max(length_of_longest_arg,
602 }
603
604 const size_t message_width = 60;
605 auto print_help_args = [&](const std::list<Argument> &args, const std::string &title) {
606 if (!args.empty())
607 {
608 stream << title << std::endl;
609 for (const auto &arg : args)
610 {
611 stream.width(length_of_longest_arg);
612 stream << std::left << arser::internal::make_comma_concatenated(arg._names) << "\t";
613 for (size_t i = 0; i < arg._help_message.size(); i++)
614 {
615 for (size_t j = 0; j < arg._help_message[i].length(); j += message_width)
616 {
617 if (i || j)
618 stream << std::string(length_of_longest_arg, ' ') << "\t";
619 stream << arg._help_message[i].substr(j, message_width) << std::endl;
620 }
621 }
622 }
623 std::cout << std::endl;
624 }
625 };
626 // positional argument
627 print_help_args(parser._positional_arg_vec, "[Positional argument]");
628 // optional argument
629 print_help_args(parser._optional_arg_vec, "[Optional argument]");
630
631 return stream;
632 }
std::string make_comma_concatenated(const std::vector< std::string > &vec)
Returns the string that created by concatenating the elements of a vector with commas.
Definition arser.h:83
std::string remove_dash(const std::string &str)
Returns the string with the leading dash removed.
Definition arser.h:71
args
Definition infer.py:21
parser
Definition infer.py:17

The documentation for this class was generated from the following file: