| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- #pragma once
- #include <string>
- #include <type_traits>
- #include <vector>
- #include <string_utils/cast.h>
- namespace program::detail {
- template <typename, typename, typename = void> struct has_cast : std::false_type {};
- template <typename T, typename S>
- struct has_cast<T, S, std::void_t<decltype(string_utils::cast(S(), std::declval<T&>()))>> : std::true_type {};
- }
- 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) {
- if (auto [rval, success] = string_utils::cast<T>(data); success) {
- return rval;
- } else {
- throw ArgumentStructureError("unable to parse", name);
- }
- }
- /**
- * \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) {
- if constexpr (detail::has_cast<T, std::string>{}) {
- if (data.size() != 1) {
- throw ArgumentStructureError("repeated option not allowed", name);
- } else {
- return convert<T>(name, data.front());
- }
- } else {
- if (auto [rval, success] = string_utils::cast<T>(data); success) {
- return rval;
- } else {
- throw ArgumentStructureError("unable to parse", name);
- }
- }
- }
- using std::to_string;
- template <typename T> std::string to_string(T const &) { return "?"; }
- inline std::string to_string(char const * str) { return str; }
- inline std::string const & to_string(std::string const & str) { return str; }
- }
|