116 lines
2.0 KiB
C++

#include <seafire/routing/match.hxx>
#include <sstream>
#include <vector>
namespace seafire::routing
{
bool
match(std::string const& subject,
std::string const& pattern,
char delim,
parameters_t& params)
{
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 || delim != *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(std::string const& pattern, parameters_t& 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("<unknown>");
}
else {
str << *p;
}
++p;
}
return str.str();
}
} // namespace seafire::routing