utilities.h 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #pragma once
  2. #include <string>
  3. #include <type_traits>
  4. #include <vector>
  5. #include <string_utils/cast.h>
  6. namespace program::detail {
  7. template <typename, typename, typename = void> struct has_cast : std::false_type {};
  8. template <typename T, typename S>
  9. struct has_cast<T, S, std::void_t<decltype(string_utils::cast(S(), std::declval<T&>()))>> : std::true_type {};
  10. }
  11. namespace program {
  12. inline std::string join(std::string const & tok,
  13. std::vector<std::string> const & data) {
  14. std::string accum = data.empty() ? "" : data.front();
  15. for (size_t i = 1; i < data.size(); ++i) {
  16. accum += tok;
  17. accum += data[i];
  18. }
  19. return accum;
  20. }
  21. template <typename T, typename = void> struct conversion_helper;
  22. /**
  23. * \brief Conversion method for positional arguments. Positional arguments are
  24. * always represented with a singular string.
  25. * \param name The name of the argument being parsed, for logging purposes
  26. * \param data A string containing the value to be processed.
  27. * \return An object of the given type
  28. */
  29. template <typename T>
  30. T convert(std::string const & name, std::string const & data) {
  31. if (auto [rval, success] = string_utils::cast<T>(data); success) {
  32. return rval;
  33. } else {
  34. throw ArgumentStructureError("unable to parse", name);
  35. }
  36. }
  37. /**
  38. * \brief Conversion method for command-line options. Because some options are
  39. * repeatable, we need to pass in a vector of objects that might be used.
  40. * \param name The name of the option being parsed, for logging purposes
  41. * \param data A vector of arguments assigned to this option.
  42. * \invariant data.size() > 0
  43. * \return An object of the given type
  44. * \throws ArgumentStructureError if the argument has been repeated but is
  45. * not a repeatable type.
  46. */
  47. template <typename T>
  48. T convert(std::string const & name, std::vector<std::string> const & data) {
  49. if constexpr (detail::has_cast<T, std::string>{}) {
  50. if (data.size() != 1) {
  51. throw ArgumentStructureError("repeated option not allowed", name);
  52. } else {
  53. return convert<T>(name, data.front());
  54. }
  55. } else {
  56. if (auto [rval, success] = string_utils::cast<T>(data); success) {
  57. return rval;
  58. } else {
  59. throw ArgumentStructureError("unable to parse", name);
  60. }
  61. }
  62. }
  63. using std::to_string;
  64. template <typename T> std::string to_string(T const &) { return "?"; }
  65. inline std::string to_string(char const * str) { return str; }
  66. inline std::string const & to_string(std::string const & str) { return str; }
  67. }