Skip to content

Latest commit

 

History

History
244 lines (199 loc) · 6.29 KB

189.md

File metadata and controls

244 lines (199 loc) · 6.29 KB
Info

Example

int main() {
   using namespace ctre::literals;
   if (const auto match = ctre::match<"([0-9]+)">("42")) {
     std::cout << match.get<1>().to_view(); // prints 42
   }
}

https://gcc.godbolt.org/z/4Ps48P

Puzzle

  • Can you implement parse_args function which returns an initialized type T based on their patterns?
template<ctll::fixed_string Pattern, class T>
struct arg {
  static constexpr auto pattern = Pattern;
  constexpr operator auto() const { return value; }
  T value;
};

template<class T>
constexpr auto parse_args(std::string_view input) -> T {
  return {}; // TODO
}

struct empty { };

struct args1 {
  arg<"num=([0-9]*)", int> num;
};

struct args2 {
  arg<"quant=([0-9]*)", int> quant;
  arg<"lab=([0-9]*)", int> lab;
};

struct args3 {
  arg<"quant=([^\\s]*)", std::string_view> quant;
  arg<"lab=([^\\s]*)", std::string_view> lab;
  arg<"num=([0-9]*)", int> num;
};

static_assert(std::is_same_v<empty, decltype(parse_args<empty>(""))>);

static_assert(42 == parse_args<args1>("num=42").num);
static_assert(4 == parse_args<args2>("quant=4 lab=2").quant);
static_assert(2 == parse_args<args2>("quant=4 lab=2").lab);

using std::literals::string_view_literals::operator""sv;
static_assert("Quant"sv == parse_args<args3>("quant=Quant lab=Lab num=42").quant);
static_assert("Lab"sv == parse_args<args3>("quant=Quant lab=Lab num=42").lab);
static_assert(42 == parse_args<args3>("quant=Quant lab=Lab num=42").num);

https://godbolt.org/z/qPao8G

Solutions

namespace detail {
template <typename T>
constexpr auto to_value(std::string_view sv) {
  return T{sv};
}

template <std::integral T>
constexpr auto to_value(std::string_view sv) {
  T ret{};
  nonstd::from_chars(std::data(sv), std::data(sv) + std::size(sv), ret);
  return ret;
}

template <class T>
constexpr auto parse_arg(std::string_view input) {
  if (const auto [whole, val] = ctre::search<T::pattern>(input); whole) {
    return T{.value = to_value<decltype(T::value)>(val)};
  } else {
    return T{};
  }
}

template <class T, template <class...> class TList, class... Args>
constexpr auto parse_args(std::string_view input, TList<Args...>) {
  return T{parse_arg<Args>(input)...};
}

} // namespace detail

template<class T>
constexpr auto parse_args(std::string_view input) -> T {
  return detail::parse_args<T>(input, detail::members_list_t<T>{});
}

https://godbolt.org/z/7W6EeY

template<class T>
constexpr auto parse_args(std::string_view input) -> T {
  return [input]<auto... Ns>(std::index_sequence<Ns...>) {
     constexpr auto tuple = to_tuple(T{});
     constexpr auto pattern = ((std::get<Ns>(tuple).pattern + ctll::fixed_string("\\s*")) + ...);
     const auto match = ctre::match<pattern>(input);
     return T{
       []<class TValue>(auto arg) {
         if constexpr (std::is_integral_v<TValue>) {
           return stoi(arg);
         } else {
           return arg;
         }
       }.template operator()<decltype(std::get<Ns>(tuple).value)>(match.template get<Ns + 1>().to_view())...
     };
  }(std::make_index_sequence<std::tuple_size_v<decltype(to_tuple(T{}))>>{});
}

https://godbolt.org/z/Tbox4b

template <class T>
constexpr auto parse_args(std::string_view input)
{
    const auto extract_match = [&input]<typename TArg>() {
        const auto [_, match] = ctre::search<TArg::pattern>(input);
        if constexpr (std::is_integral_v<typename TArg::value_t>) {
            return detail::stoi(match);
        } else {
            return match;
        }
    };

    auto output = T {};
    if constexpr (requires { output.num; }) {
        output.num = extract_match.template operator()<decltype(T {}.num)>();
    }
    if constexpr (requires { output.quant; }) {
        output.quant = extract_match.template operator()<decltype(T {}.quant)>();
    }
    if constexpr (requires { output.lab; }) {
        output.lab = extract_match.template operator()<decltype(T {}.lab)>();
    }
    return output;
}

https://godbolt.org/z/5W3vG4

namespace detail {
template <typename>
constexpr auto parse_arg(auto arg) {
  return arg;
}

template <typename T> requires std::is_integral_v<T>
constexpr auto parse_arg(auto arg) {
  return stoi(arg);
}
} // namespace detail

template <typename T>
constexpr auto parse_args(std::string_view input) {
  constexpr auto members = detail::make_members_tuple<T>();

  auto expand_args = [&]<auto... Ns>(std::index_sequence<Ns...>) -> T {
    return {
      detail::parse_arg<decltype(std::get<Ns>(members).value)>(
        ctre::search<std::get<Ns>(members).pattern>(input)
          .template get<1>()
          .to_view())...};
  };

  return expand_args(
    std::make_index_sequence<std::tuple_size_v<decltype(members)>>{});
}

https://godbolt.org/z/7KKcbW

template<class T>
constexpr T fromSV(std::string_view input);

template<>
constexpr std::string_view fromSV<std::string_view>(std::string_view input) {
    return input;
}

template<>
constexpr int fromSV<int>(std::string_view input) {
    int v = 0;
    for(size_t i=0; i<input.size(); i++)
        v = v*10 + (input[i]-'0');
    return v;
}

template<ctll::fixed_string Pattern, class T>
struct arg {
  constexpr arg(std::string_view input) {
    if (const auto match = ctre::search<pattern>(input))
      value = fromSV<T>( match.template get<1>().to_view());
    else
      value = {};
  };
  static constexpr auto pattern = Pattern;
  constexpr operator auto() const { return value; }
  T value;
};

template<class T>
constexpr auto parse_args(std::string_view input) -> T {
  using sv = std::string_view;
  if constexpr (std::is_constructible<T, sv, sv, sv>::value)
    return {input,input,input};
  if constexpr (std::is_constructible<T, sv, sv>::value)
    return {input, input};
  if constexpr (std::is_constructible<T, sv>::value)
    return {input};
}

struct empty { };

template<>
constexpr auto parse_args<empty>(std::string_view input) -> empty {
    return empty{};
}

https://godbolt.org/z/dhGPj7