#include #include #include #include namespace seafire::routing { bool match_path(std::string const& pattern, std::string const& subject, route_parameters_t& params) { route_parameters_t tmp_params; // p/pend = pattern iterators. // auto p = pattern.begin(); auto const pend = pattern.end(); // s/send = subject iterators. // auto s = subject.begin(); auto const send = subject.end(); auto match_param = [&]() { // k/kend = local pattern iterators. // auto const k = p; while (p != pend && '}' != *p) { ++p; } auto const kend = p; ++p; if (k == kend) { throw std::invalid_argument{"empty parameter name"}; } // a greedy parameter will eat the rest of the subject. // bool const greedy{'*' == *k && 1 == std::distance(k, kend)}; // v/vend = local subject iterators. // auto const v = s; while (s != send && (greedy || '/' != *s)) { ++s; } auto const vend = s; tmp_params.map().emplace(std::string{k, kend}, std::string{v, vend}); }; while (p != pend) { if (*p == '{') { ++p; match_param(); continue; } if (s == send) { break; } if (*p != *s) { return false; } ++p; ++s; } if (p != pend || s != send) { return false; } params = std::move(tmp_params); return true; } std::string render_path(std::string const& pattern, route_parameters_t const& params) { std::stringstream str; auto p = pattern.begin(); auto pend = pattern.end(); while (p != pend) { if (*p == '{') { ++p; auto const k = p; while (p != pend && '}' != *p) { ++p; } auto const kend = p; str << params.get(std::string{k, kend}).value_or(""); } else { str << *p; } ++p; } return str.str(); } } // namespace seafire::routing