Skip to content

Instantly share code, notes, and snippets.

@zxmarcos
Created March 29, 2018 19:41
Show Gist options
  • Save zxmarcos/61d6f16847b96310d11c69c8812dfd38 to your computer and use it in GitHub Desktop.
Save zxmarcos/61d6f16847b96310d11c69c8812dfd38 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <functional>
#include <tuple>
#include <utility>
#include <regex>
#include <vector>
using namespace std;
namespace detail {
struct url_matcher {
string url;
regex pattern;
url_matcher(const string &surl) : url(surl) {
regex parameters("(<[^>]+>)", regex_constants::ECMAScript);
string str_pattern = string("^") + regex_replace(surl, parameters, "([^/]+)") + string("$");
pattern = regex(str_pattern, regex_constants::ECMAScript);
cout << str_pattern << endl;
}
bool matches(const string &url) {
return regex_search(url, pattern);
}
vector<string> extract(const string &url) const {
vector<string> values;
smatch matcher;
if (regex_match(url, matcher, pattern)) {
cout << "EXTRACT " << matcher[0].str() << endl;
for (size_t i = 1; i < matcher.size(); i++) {
values.push_back(matcher[i].str());
}
}
return values;
}
};
template <typename T>
void reader(T &result, const string &value)
{
// static_assert(false, "XPTO router: URL reader for type not implemented!");
}
template <>
void reader(int &result, const string &value)
{
result = stoi(value);
}
template<>
void reader(string &result, const string &value)
{
result = value;
}
}
struct xpto_router {
function<void(const string &url)> cb;
vector<pair<detail::url_matcher, function<void(const string &)>>> routes;
template<typename F, typename T, size_t...index>
static void invoke_helper(F&& f, T&& args, index_sequence<index...>)
{
f(get<index>(forward<T>(args))...);
}
template<size_t index, typename ArgList>
int parse_value_impl(ArgList &args, const vector<string> &values)
{
if (index < values.size()) {
detail::reader<typename tuple_element<index, ArgList>::type>(get<index>(args), values[index]);
}
return 0;
}
template<typename ArgList, size_t...index>
auto parse(ArgList& args, const vector<string> &values, index_sequence<index...>)
{
auto x = { parse_value_impl<index>(args, values)... };
(void ) x;
}
template <typename ArgList>
ArgList parse_arguments(const vector<string> &values)
{
using Size = integral_constant<size_t, tuple_size<ArgList>::value>;
if (values.size() != Size::value) {
throw runtime_error("Arguments mistmatch!");
}
ArgList args;
parse<ArgList>(args, values, make_index_sequence<Size::value>{});
return args;
}
template <typename RouterF, typename...Args>
void bind(const string url, RouterF f(Args...)) {
using ArgList = tuple<Args...>;
auto url_matcher = detail::url_matcher(url);
routes.emplace_back(make_pair(url_matcher, [=](const string &url) {
invoke_helper(f,
parse_arguments<ArgList>(url_matcher.extract(url)),
make_index_sequence<tuple_size<ArgList>::value>{});
}));
}
void dispatch(const string url) {
for (auto &it : routes) {
if (it.first.matches(url)) {
it.second(url);
break;
}
}
}
};
void foo(int a) {
cout << a << endl;
}
void bar(int a, string b) {
cout << a << b << endl;
}
void test(int a, int c) {
cout << "test" << endl;
}
int main(int, char **)
{
xpto_router router;
router.bind("/<id>", foo);
router.bind("/test/<x>", test);
router.bind("/<id>/<name>", bar);
router.dispatch("/42");
router.dispatch("/42/jose");
try {
router.dispatch("/test/1");
} catch (const std::exception &e) {
cout << e.what() << endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment