61 return std::isspace(ch) == 0;
67lcount(
const std::string& s,
bool (*f)(
int) = not_is_space)
70 for(
size_t i = 0; i < s.length(); ++i, ++c)
83 s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
92 s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
111 auto slen = strlen(s);
112 auto* result =
new char[slen + 1];
115 memcpy(result, s, slen *
sizeof(
char));
124template <
typename InputIt>
128 std::ostringstream ss;
146 auto _nidx = arg.find_first_of(
"0123456789");
147 auto _oidx = arg.find_first_not_of(
"0123456789.Ee+-*/");
150 if(_nidx == std::string::npos)
154 if(_oidx != std::string::npos)
166 for(
size_t i = 0; i < s.length(); ++i)
171 if(std::ispunct(
static_cast<int>(s[i])) != 0)
175 return static_cast<int>(i);
177 if(s[i] ==
'_' || s[i] ==
'-')
193 for(i = 0; i < s.length(); ++i)
195 if((std::ispunct(
static_cast<int>(s[i])) != 0) && s[i] !=
'-')
205namespace is_container_impl
209struct is_container : std::false_type
212template <
typename... Args>
213struct is_container<
std::vector<Args...>> : std::true_type
215template <
typename... Args>
216struct is_container<
std::set<Args...>> : std::true_type
218template <
typename... Args>
219struct is_container<
std::deque<Args...>> : std::true_type
221template <
typename... Args>
222struct is_container<
std::list<Args...>> : std::true_type
226struct is_initializing_container : is_container<T>::type
229template <
typename... Args>
230struct is_initializing_container<
std::initializer_list<Args...>> : std::true_type
240 static constexpr bool const value =
241 is_container_impl::is_container<decay_t<T>>::value;
248struct is_initializing_container
250 static constexpr bool const value =
251 is_container_impl::is_initializing_container<decay_t<T>>::value;
271 struct c_args : std::tuple<int, char**, std::string>
274 template <
typename... Args>
279 auto&
argc() {
return std::get<0>(*
this); }
280 auto&
argv() {
return std::get<1>(*
this); }
281 auto&
args() {
return std::get<2>(*
this); }
283 const auto&
argc()
const {
return std::get<0>(*
this); }
284 const auto&
argv()
const {
return std::get<1>(*
this); }
285 const auto&
args()
const {
return std::get<2>(*
this); }
290 for(
int i = 0; i <
argc(); ++i)
291 argv()[i] = (
delete[]
argv()[i],
nullptr);
292 argv() = (
delete[]
argv(),
nullptr);
299 template <
typename... Args>
344 , m_what(std::move(err))
347 operator bool()
const {
return m_error; }
354 bool m_error =
false;
379 m_names.push_back(
name);
385 for(
const auto& itr :
names)
386 m_names.push_back(itr);
410 if(
position != Position::LastArgument)
441 template <
typename T>
445 m_default_tidx = std::type_index{
typeid(
decay_t<T>) };
446 m_callback = [&](
void*& obj) {
449 obj = (
void*)
new T{};
450 (*
static_cast<T*
>(obj)) = val;
452 m_destroy = [](
void*& obj) {
454 delete static_cast<T*
>(obj);
459 template <
typename T>
463 m_default_tidx = std::type_index{
typeid(
decay_t<T>) };
464 m_callback = [&](
void*& obj) { obj = (
void*) &val; };
468 template <
typename T>
471 for(
auto&& itr : _choices)
473 std::stringstream ss;
475 m_choices.insert(ss.str());
480 template <
template <
typename...>
class ContainerT,
typename T,
typename... ExtraT,
481 typename ContT = ContainerT<T, ExtraT...>,
485 for(
auto&& itr : _choices)
487 std::stringstream ss;
489 m_choices.insert(ss.str());
494 template <
typename ActionFuncT>
497 m_actions.push_back(std::forward<ActionFuncT>(_func));
501 bool found()
const {
return m_found; }
503 template <
typename T>
504 std::enable_if_t<helpers::is_container<T>::value, T>
get()
507 typename T::value_type vt;
508 for(
auto& s : m_values)
510 std::istringstream in(s);
512 t.insert(t.end(), vt);
514 if(m_values.empty() && m_default &&
515 m_default_tidx == std::type_index{ typeid(T) })
516 t = (*
static_cast<T*
>(m_default));
520 template <
typename T>
522 !helpers::is_container<T>::value && !std::is_same<T, bool>::value, T>
525 auto inp = get<std::string>();
526 std::istringstream iss{ inp };
529 if(inp.empty() && m_default && m_default_tidx == std::type_index{ typeid(T) })
530 t = (*
static_cast<T*
>(m_default));
534 template <
typename T>
535 std::enable_if_t<std::is_same<T, bool>::value, T>
get()
540 auto inp = get<std::string>();
541 if(inp.empty() && m_default && m_default_tidx == std::type_index{ typeid(T) })
542 return (*
static_cast<T*
>(m_default));
549 size_t size()
const {
return m_values.size(); }
553 std::stringstream ss;
554 for(
const auto& itr : m_names)
556 return ss.str().substr(1);
561 : m_desc(
std::move(desc))
564 m_names.push_back(
name);
567 argument() =
default;
571 if(!m_choices.empty())
573 if(m_choices.find(value) == m_choices.end())
575 std::stringstream ss;
576 ss <<
"Invalid choice: '" << value <<
"'. Valid choices: ";
577 for(
const auto& itr : m_choices)
578 ss <<
"'" << itr <<
"' ";
579 return arg_result(ss.str());
587 for(
auto& itr : m_actions)
593 std::stringstream ss;
595 for(
const auto& itr : arg.m_names)
597 ss <<
", index: " << arg.m_index <<
", count: " << arg.m_count
598 <<
", min count: " << arg.m_min_count <<
", max count: " << arg.m_max_count
599 <<
", found: " << std::boolalpha << arg.m_found
600 <<
", required: " << std::boolalpha << arg.m_required
601 <<
", position: " << arg.m_position <<
", values: ";
602 for(
const auto& itr : arg.m_values)
609 int m_position = Position::IgnoreArgument;
610 int m_count = Count::ANY;
611 int m_min_count = Count::ANY;
612 int m_max_count = Count::ANY;
613 std::vector<std::string> m_names = {};
616 bool m_found =
false;
617 bool m_required =
false;
619 std::type_index m_default_tidx = std::type_index{
typeid(void) };
620 void* m_default =
nullptr;
623 std::set<std::string> m_choices = {};
624 std::vector<std::string> m_values = {};
625 std::vector<action_func_t> m_actions = {};
631 : m_desc(
std::move(desc))
638 m_arguments.push_back({});
639 m_arguments.back().m_index =
static_cast<int>(m_arguments.size()) - 1;
640 return m_arguments.back();
663 m_positional_arguments.push_back({});
664 auto& _entry = m_positional_arguments.back();
667 _entry.m_index = m_positional_arguments.size();
673 template <
typename Tp>
676 if(m_positional_values.find(_idx) == m_positional_values.end())
677 return arg_result{
"Positional value not found at index " +
678 std::to_string(_idx) };
679 if(_idx >= m_positional_arguments.size())
680 return arg_result{
"No positional argument was specified for index " +
681 std::to_string(_idx) };
682 _value = m_positional_arguments.at(_idx).get<Tp>();
688 template <
typename Tp>
692 for(
size_t i = 0; i < m_positional_values.size(); ++i)
694 if(i >= m_positional_arguments.size())
698 auto& itr = m_positional_arguments.at(i);
699 for(
auto& nitr : itr.m_names)
702 return get(i, _value);
707 for(
auto& itr : m_positional_arguments)
709 for(
auto& nitr : itr.m_names)
714 itr.m_default_tidx == std::type_index{ typeid(decay_t<Tp>) })
715 _value = (*
static_cast<Tp*
>(itr.m_default));
716 else if(itr.m_required)
718 _name +
" not parsed from the command line (required)"
725 return arg_result{ _name +
" is not a named positional argument" };
730 template <
typename BoolFuncT,
typename ActionFuncT>
734 { std::forward<BoolFuncT>(_b), std::forward<ActionFuncT>(_act) });
740 template <
typename ActionFuncT>
744 m_actions.push_back({ _b, std::forward<ActionFuncT>(_act) });
766 int verbose_level = 0)
775 int verbose_level = 0)
796 const std::string& _delim =
"--",
int verbose_level = 0);
835 int verbose_level = 0);
839 template <
typename... Args>
842 return parse(std::forward<Args>(args)...);
849 std::vector<std::string>
_args;
851 for(
int i = 0; i < argc; ++i)
852 _args.emplace_back((
const char*)
argv[i]);
865 arg_result
parse(
const std::vector<std::string>&
_args,
int verbose_level = 0);
873 m_help_enabled =
true;
875 .
names({
"-h",
"-?",
"--help" })
915 name, [](
int c) ->
bool {
return c !=
static_cast<int>(
'-'); });
916 auto itr = m_name_map.find(n);
917 if(itr != m_name_map.end())
918 return m_arguments[
static_cast<size_t>(itr->second)].m_found;
949 template <
typename T>
952 auto itr = m_name_map.find(name);
953 if(itr != m_name_map.end())
954 return m_arguments[
static_cast<size_t>(itr->second)].get<T>();
962 auto itr = m_name_map.find(name);
963 if(itr != m_name_map.end())
964 return m_arguments[
static_cast<size_t>(itr->second)].size();
978 template <
typename ErrorFuncT>
981 on_error_sfinae(std::forward<ErrorFuncT>(_func), 0);
992 template <
typename FuncT = std::function<
bool(
int,
int)>>
993 arg_result check_count(argument& a,
const std::string& _do_str =
"111",
994 const FuncT& _func = std::not_equal_to<int>{})
996 int _sz =
static_cast<int>(a.m_values.size());
997 int _cnt = a.m_count;
998 int _max = a.m_max_count;
999 int _min = a.m_min_count;
1001 std::bitset<3> _do{ _do_str };
1002 std::bitset<3> _checks;
1005 _checks.set(0, _do.test(0) && _cnt > argument::Count::ANY && _func(_sz, _cnt));
1006 _checks.set(1, _do.test(1) && _max > argument::Count::ANY && _sz > _max);
1007 _checks.set(2, _do.test(2) && _min > argument::Count::ANY && _sz < _min);
1010 return arg_result{};
1012 std::stringstream msg;
1013 msg <<
"Argument: " << a.get_name() <<
" failed to satisfy its argument count "
1014 <<
"requirements. Number of arguments: " << _sz <<
".";
1017 msg <<
"\n[" << a.get_name() <<
"]> Requires exactly " << _cnt <<
" values.";
1023 msg <<
"\n[" << a.get_name() <<
"]> Requires less than " << _max + 1
1028 msg <<
"\n[" << a.get_name() <<
"]> Requires more than " << _min - 1
1032 return arg_result(msg.str());
1037 template <
typename FuncT = std::function<
bool(
int,
int)>>
1039 const FuncT& _func = std::not_equal_to<int>{})
1041 auto itr = m_name_map.find(name);
1042 if(itr != m_name_map.end())
1043 return check_count(m_arguments[
static_cast<size_t>(itr->second)], _do, _func);
1044 return arg_result{};
1049 template <
typename ErrorFuncT>
1050 auto on_error_sfinae(ErrorFuncT&& _func,
int)
1051 ->
decltype(_func(std::declval<this_type&>(), std::declval<result_type>()),
1054 m_error_func = std::forward<ErrorFuncT>(_func);
1059 template <
typename ErrorFuncT>
1060 auto on_error_sfinae(ErrorFuncT&& _func,
long)
1061 ->
decltype(_func(std::declval<result_type>()), void())
1064 m_error_func = _wrap_func;
1069 arg_result begin_argument(
const std::string& arg,
bool longarg,
int position);
1070 arg_result add_value(
const std::string& value,
int location);
1071 arg_result end_argument();
1076 bool m_help_enabled =
false;
1082 std::vector<argument> m_arguments = {};
1083 std::map<int, int> m_positional_map = {};
1084 std::map<std::string, int> m_name_map = {};
1085 std::vector<action_pair_t> m_actions = {};
1086 std::vector<argument> m_positional_arguments = {};
1087 std::map<int, std::string> m_positional_values = {};
1094argument_parser::argument::get<std::string>()
1097 if(m_values.empty() && m_default !=
nullptr &&
1098 m_default_tidx == std::type_index{ typeid(T) })
1099 return (*
static_cast<T*
>(m_default));
1100 return helpers::join(m_values.begin(), m_values.end());
1106inline std::vector<std::string>
1107argument_parser::argument::get<std::vector<std::string>>()
1109 using T = std::vector<std::string>;
1110 if(m_values.empty() && m_default !=
nullptr &&
1111 m_default_tidx == std::type_index{
typeid(T) })
1112 return (*
static_cast<T*
>(m_default));
1121#if defined(TIMEMORY_UTILITY_HEADER_MODE)
::tim::statistics< Tp > max(::tim::statistics< Tp > lhs, const Tp &rhs)
typename std::enable_if< B, T >::type enable_if_t
auto join(const char *sep, Arg &&arg, Args &&... args)
std::array< char *, 4 > _args
bool get_bool(const std::string &strbool, bool _default) noexcept
typename std::decay< T >::type decay_t
Alias template for decay.
typename std::enable_if< B, T >::type enable_if_t
Alias template for enable_if.
tim::mpl::apply< std::string > string
const std::string std::ostream * os
description("A generic option for any setting. Each argument MUST be passed in " "form: 'NAME=VALUE'. E.g. --timemory-args " "\"papi_events=PAPI_TOT_INS,PAPI_TOT_CYC\" text_output=off") .action([&](parser_t &p)
friend std::ostream & operator<<(std::ostream &os, const arg_result &dt)
const std::string & what() const
arg_result(std::string err) noexcept
friend std::ostream & operator<<(std::ostream &os, const argument &arg)
argument & max_count(int count)
argument & min_count(int count)
argument & required(bool req)
argument & position(int position)
friend struct argument_parser
argument & set_default(const T &val)
std::enable_if_t< std::is_same< T, bool >::value, T > get()
argument & description(const std::string &description)
argument & count(int count)
std::enable_if_t< !helpers::is_container< T >::value &&!std::is_same< T, bool >::value, T > get()
argument & choices(const ContainerT< T, ExtraT... > &_choices)
argument & dtype(const std::string &_dtype)
std::function< void(void *&)> callback_t
argument & name(const std::string &name)
argument & action(ActionFuncT &&_func)
argument & names(const std::vector< std::string > &names)
std::string get_name() const
argument & choices(const std::initializer_list< T > &_choices)
std::enable_if_t< helpers::is_container< T >::value, T > get()
argument & set_default(T &val)
void on_error(ErrorFuncT &&_func)
bool exists(const std::string &name) const
Returns whether or not an option was found in the arguments. Only useful after a call to parse or par...
int64_t get_positional_count() const
std::pair< bool_func_t, action_func_t > action_pair_t
known_args_t parse_known_args(int argc, char **argv, const std::string &_delim="--", int verbose_level=0)
Basic variant of parse_known_args which does not replace argc/argv and does not provide an array of s...
argument & add_argument(const std::initializer_list< std::string > &_names, const std::string &desc, bool req=false)
int64_t get_count(const std::string &name)
void set_help_width(int _v)
this_type & add_action(const std::string &_name, ActionFuncT &_act)
arg_result get(const std::string &_name, Tp &_value)
arg_result get(size_t _idx, Tp &_value)
argument & add_positional_argument(const std::string &_name)
std::tuple< arg_result, int, char ** > known_args_t
this_type & add_action(BoolFuncT &&_b, ActionFuncT &_act)
arg_result parse(int argc, char **argv, int verbose_level=0)
void print_help(const std::string &_extra="")
argument & enable_help()
Add a help command.
static int64_t get_count(argument &a)
std::set< std::string > strset_t
std::function< bool(this_type &)> bool_func_t
std::vector< std::string > strvec_t
T get(const std::string &name)
Get the value(s) associated with an argument. If option, it should be used in conjunction with exists...
argument_parser this_type
argument & add_argument()
argument_parser(std::string desc)
arg_result parse_known_args(int *argc, char ***argv, const std::string &_delim="--", int verbose_level=0)
This variant calls parse_known_args and replaces argc and argv with the argv[0] + anything after deli...
arg_result parse_args(Args &&... args)
std::function< void(this_type &, arg_result &)> error_func_t
std::function< void(this_type &)> action_func_t
argument & add_argument(const std::vector< std::string > &_names, const std::string &desc, bool req=false)
std::tuple< int, char **, std::string > base_type
const auto & args() const
const auto & argv() const
const auto & argc() const
This class exists to simplify creating argument arrays compatible with execv* routines and MPI_Comm_s...
static void free_execv(cargs_t &itr)
argument_vector(Args &&... args)
cargs_t get_execv(const base_type &_prepend, size_t _beg=0, size_t _end=std::numeric_limits< size_t >::max()) const
std::vector< std::string > base_type
char * strdup(const char *s)