aboutsummaryrefslogtreecommitdiffstats
path: root/routing.h
diff options
context:
space:
mode:
authoripknHama <ipknhama@gmail.com>2014-04-15 00:31:51 +0900
committeripknHama <ipknhama@gmail.com>2014-04-15 00:31:51 +0900
commit53debf7e2cb494d8ea89205812bf792e8e9354da (patch)
treec0195ecc0673b794087c99908a2314dfc8a0ff31 /routing.h
parent7ec586556e348725bff3919f4787a75d71c520fa (diff)
downloadcrow-53debf7e2cb494d8ea89205812bf792e8e9354da.tar.gz
crow-53debf7e2cb494d8ea89205812bf792e8e9354da.zip
parameter passing done for int
Diffstat (limited to 'routing.h')
-rw-r--r--routing.h197
1 files changed, 134 insertions, 63 deletions
diff --git a/routing.h b/routing.h
index 8c3cc99..62f7d80 100644
--- a/routing.h
+++ b/routing.h
@@ -2,12 +2,12 @@
#include <cstdint>
#include <utility>
-#include <string>
#include <tuple>
#include <unordered_map>
#include <memory>
#include <boost/lexical_cast.hpp>
+#include "common.h"
#include "http_response.h"
//TEST
@@ -36,7 +36,8 @@ namespace flask
virtual void validate()
{
}
- virtual response handle(const request&)
+
+ virtual response handle(const request&, const routing_params&)
{
return response(400);
}
@@ -89,7 +90,7 @@ namespace flask
}
}
- response handle(const request&)
+ response handle(const request&, const routing_params&)
{
return handler_();
}
@@ -101,6 +102,33 @@ namespace flask
template <typename ... Args>
class TaggedRule : public BaseRule
{
+ private:
+ template <typename F, int NInt, int NUint, int NDouble, int NString, typename S1, typename S2> struct call
+ {
+ };
+
+ template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1, typename ... Args2>
+ struct call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>, black_magic::S<Args2...>>
+ {
+ response operator()(F& handler, const routing_params& params)
+ {
+ using pushed = typename black_magic::S<Args2...>::template push_back<call_pair<int64_t, NInt>>;
+ return call<F, NInt+1, NUint, NDouble, NString,
+ black_magic::S<Args1...>, pushed>()(handler, params);
+ }
+ };
+
+ template <typename F, int NInt, int NUint, int NDouble, int NString, typename ... Args1>
+ struct call<F, NInt, NUint, NDouble, NString, black_magic::S<>, black_magic::S<Args1...>>
+ {
+ response operator()(F& handler, const routing_params& params)
+ {
+ return handler(
+ params.get<typename Args1::type>(Args1::pos)...
+ );
+ //return response(500);
+ }
+ };
public:
TaggedRule(std::string rule)
: BaseRule(std::move(rule))
@@ -134,38 +162,41 @@ namespace flask
};
}
- response handle(const request&)
+ response handle(const request&, const routing_params& params)
{
//return handler_();
- return response(500);
+ return call<decltype(handler_), 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(handler_, params);
+ //return response(500);
}
private:
std::function<response(Args...)> handler_;
+
+ template <typename T, int Pos>
+ struct call_pair
+ {
+ using type = T;
+ static const int pos = Pos;
+ };
+
};
- constexpr const size_t INVALID_RULE_INDEX{static_cast<size_t>(-1)};
class Trie
{
public:
struct Node
{
- std::unordered_map<std::string, size_t> children;
- size_t rule_index{INVALID_RULE_INDEX};
- size_t child_for_int{INVALID_RULE_INDEX};
- size_t child_for_uint{INVALID_RULE_INDEX};
- size_t child_for_float{INVALID_RULE_INDEX};
- size_t child_for_str{INVALID_RULE_INDEX};
- size_t child_for_path{INVALID_RULE_INDEX};
+ std::unordered_map<std::string, unsigned> children;
+ unsigned rule_index{};
+ std::array<unsigned, (int)ParamType::MAX> param_childrens{};
bool IsSimpleNode() const
{
return
- rule_index == INVALID_RULE_INDEX &&
- child_for_int == INVALID_RULE_INDEX &&
- child_for_uint == INVALID_RULE_INDEX &&
- child_for_float == INVALID_RULE_INDEX &&
- child_for_str == INVALID_RULE_INDEX &&
- child_for_path == INVALID_RULE_INDEX;
+ !rule_index &&
+ std::all_of(
+ std::begin(param_childrens),
+ std::end(param_childrens),
+ [](unsigned x){ return !x; });
}
};
@@ -183,20 +214,59 @@ private:
}
}
-public:
void optimize()
{
optimizeNode(head());
}
- size_t find(const request& req, const Node* node = nullptr, size_t pos = 0) const
+public:
+ void validate()
+ {
+ if (!head()->IsSimpleNode())
+ throw std::runtime_error("Internal error: Trie header should be simple!");
+ optimize();
+ }
+
+ std::pair<unsigned, routing_params> find(const request& req, const Node* node = nullptr, unsigned pos = 0, routing_params* params = nullptr) const
{
- size_t found = INVALID_RULE_INDEX;
+ routing_params empty;
+ if (params == nullptr)
+ params = &empty;
+
+ unsigned found{};
+ routing_params match_params;
if (node == nullptr)
node = head();
if (pos == req.url.size())
- return node->rule_index;
+ return {node->rule_index, *params};
+
+ auto update_found = [&found, &match_params](std::pair<unsigned, routing_params>& ret)
+ {
+ if (ret.first && (!found || found > ret.first))
+ {
+ found = ret.first;
+ match_params = ret.second;
+ }
+ };
+
+ if (node->param_childrens[(int)ParamType::INT])
+ {
+ char c = req.url[pos];
+ if ((c >= '0' && c <= '9') || c == '+' || c == '-')
+ {
+ char* eptr;
+ errno = 0;
+ long long int value = strtoll(req.url.data()+pos, &eptr, 10);
+ if (errno != ERANGE && eptr != req.url.data()+pos)
+ {
+ params->int_params.push_back(value);
+ auto ret = find(req, &nodes_[node->param_childrens[(int)ParamType::INT]], eptr - req.url.data(), params);
+ update_found(ret);
+ params->int_params.pop_back();
+ }
+ }
+ }
for(auto& kv : node->children)
{
@@ -205,55 +275,53 @@ public:
if (req.url.compare(pos, fragment.size(), fragment) == 0)
{
- size_t ret = find(req, child, pos + fragment.size());
- if (ret != INVALID_RULE_INDEX && (found == INVALID_RULE_INDEX || found > ret))
- {
- found = ret;
- }
+ auto ret = find(req, child, pos + fragment.size(), params);
+ update_found(ret);
}
}
- return found;
+ return {found, std::move(match_params)};
}
- void add(const std::string& url, size_t rule_index)
+ void add(const std::string& url, unsigned rule_index)
{
- size_t idx{0};
+ unsigned idx{0};
- for(size_t i = 0; i < url.size(); i ++)
+ for(unsigned i = 0; i < url.size(); i ++)
{
char c = url[i];
if (c == '<')
{
- if (url.compare(i, 5, "<int>") == 0)
- {
- idx = nodes_[idx].child_for_int = new_node();
- i += 5;
- }
- else if (url.compare(i, 6, "<uint>") == 0)
- {
- idx = nodes_[idx].child_for_uint = new_node();
- i += 6;
- }
- else if (url.compare(i, 7, "<float>") == 0 ||
- url.compare(i, 8, "<double>") == 0)
+ bool found = false;
+
+ static struct ParamTraits
{
- idx = nodes_[idx].child_for_float = new_node();
- i += 7;
- }
- else if (url.compare(i, 5, "<str>") == 0)
+ ParamType type;
+ std::string name;
+ } paramTraits[] =
{
- idx = nodes_[idx].child_for_str = new_node();
- i += 5;
- }
- else if (url.compare(i, 6, "<path>") == 0)
+ { ParamType::INT, "<int>" },
+ { ParamType::UINT, "<uint>" },
+ { ParamType::DOUBLE, "<float>" },
+ { ParamType::DOUBLE, "<double>" },
+ { ParamType::STRING, "<str>" },
+ { ParamType::PATH, "<path>" },
+ };
+
+ for(auto it = begin(paramTraits); it != end(paramTraits); ++it)
{
- idx = nodes_[idx].child_for_path = new_node();
- i += 6;
+ if (url.compare(i, it->name.size(), it->name) == 0)
+ {
+ idx = nodes_[idx].param_childrens[(int)it->type] = new_node();
+ i += it->name.size();
+ found = true;
+ break;
+ }
}
- else
+
+ if (!found)
{
- throw std::runtime_error("Invalid url: " + url + " (" + boost::lexical_cast<std::string>(i) + ")");
+ throw std::runtime_error("Invalid parameter type: " + url + " (" + boost::lexical_cast<std::string>(i) + ")");
}
i --;
}
@@ -267,7 +335,7 @@ public:
idx = nodes_[idx].children[piece];
}
}
- if (nodes_[idx].rule_index != INVALID_RULE_INDEX)
+ if (nodes_[idx].rule_index)
throw std::runtime_error("handler already exists for " + url);
nodes_[idx].rule_index = rule_index;
}
@@ -282,7 +350,7 @@ public:
return &nodes_.front();
}
- size_t new_node()
+ unsigned new_node()
{
nodes_.resize(nodes_.size()+1);
return nodes_.size() - 1;
@@ -294,6 +362,7 @@ public:
class Router
{
public:
+ Router() : rules_(1) {}
template <uint64_t N>
typename black_magic::arguments<N>::type::template rebind<TaggedRule>& new_rule_tagged(const std::string& rule)
{
@@ -314,24 +383,26 @@ public:
void validate()
{
- trie_.optimize();
+ trie_.validate();
for(auto& rule:rules_)
{
- rule->validate();
+ if (rule)
+ rule->validate();
}
}
response handle(const request& req)
{
- size_t rule_index = trie_.find(req);
+ auto found = trie_.find(req);
+ unsigned rule_index = found.first;
- if (rule_index == INVALID_RULE_INDEX)
+ if (!rule_index)
return response(404);
if (rule_index >= rules_.size())
throw std::runtime_error("Trie internal structure corrupted!");
- return rules_[rule_index]->handle(req);
+ return rules_[rule_index]->handle(req, found.second);
}
private:
std::vector<std::unique_ptr<BaseRule>> rules_;