| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- #pragma once
- #include <string>
- #include <type_traits>
- #include <vector>
- namespace program::traits {
- template <typename T, typename = void>
- struct is_repeatable : std::false_type {};
- template <typename F>
- struct is_repeatable<F, std::enable_if_t<!std::is_void_v<
- std::result_of_t<F(std::vector<std::string>)>>>>
- : std::true_type {};
- template <typename T>
- constexpr bool const is_repeatable_v = is_repeatable<T>::value;
- }
- namespace program {
- inline std::string join(std::string const & tok,
- std::vector<std::string> const & data) {
- std::string accum = data.empty() ? "" : data.front();
- for (size_t i = 1; i < data.size(); ++i) {
- accum += tok;
- accum += data[i];
- }
- return accum;
- }
- template <typename T, typename = void> struct conversion_helper;
- /**
- * \brief Conversion method for positional arguments. Positional arguments are
- * always represented with a singular string.
- * \param name The name of the argument being parsed, for logging purposes
- * \param data A string containing the value to be processed.
- * \return An object of the given type
- */
- template <typename T>
- T convert(std::string const & name, std::string const & data) {
- return conversion_helper<T>{}(data);
- }
- /**
- * \brief Conversion method for command-line options. Because some options are
- * repeatable, we need to pass in a vector of objects that might be used.
- * \param name The name of the option being parsed, for logging purposes
- * \param data A vector of arguments assigned to this option.
- * \invariant data.size() > 0
- * \return An object of the given type
- * \throws ArgumentStructureError if the argument has been repeated but is
- * not a repeatable type.
- */
- template <typename T>
- T convert(std::string const & name, std::vector<std::string> const & data) {
- conversion_helper<T> helper;
- if constexpr (!traits::is_repeatable_v<decltype(helper)>) {
- return helper(data);
- } else if (data.size() == 1) {
- return helper(data.front());
- }
- throw ArgumentStructureError("Repeated option not allowed", name);
- }
- template <typename T>
- struct conversion_helper<
- T, std::enable_if_t<std::is_convertible_v<std::string, T>>> {
- T operator()(std::string const & str) const { return T(str); }
- };
- template <> struct conversion_helper<int> {
- int operator()(std::string const & str) const { return std::stoi(str); }
- };
- template <typename T>
- struct conversion_helper<std::vector<T>> : conversion_helper<T> {
- std::vector<T> operator()(std::vector<std::string> const & data) const {
- std::vector<T> rval;
- for (auto & str : data) {
- rval.emplace_back((*this)(str));
- }
- return rval;
- }
- };
- }
|