routing class working version

This commit is contained in:
ipknHama 2014-04-03 05:31:32 +09:00
parent 5e5d696884
commit d533a619c9
3 changed files with 126 additions and 22 deletions

110
routing.h
View File

@ -1,6 +1,9 @@
#pragma once
#include <cstdint>
#include <utility>
#include <string>
#include <tuple>
#include "utility.h"
@ -8,32 +11,121 @@ namespace flask
{
namespace black_magic
{
constexpr bool is_equ_n(StrWrap a, int ai, StrWrap b, int bi, int n)
constexpr bool is_equ_n(const_str a, int ai, const_str b, int bi, int n)
{
return n == 0 ? true : a[ai] != b[bi] ? false : is_equ_n(a,ai+1,b,bi+1,n-1);
return
ai + n > a.size() || bi + n > b.size()
? false :
n == 0
? true :
a[ai] != b[bi]
? false :
is_equ_n(a,ai+1,b,bi+1,n-1);
}
constexpr bool is_int(StrWrap s, int i)
constexpr bool is_int(const_str s, int i)
{
return is_equ_n(s, i, "<int>", 0, 5);
}
constexpr bool is_str(StrWrap s, int i)
constexpr bool is_float(const_str s, int i)
{
return is_equ_n(s, i, "<float>", 0, 7) ||
is_equ_n(s, i, "<double>", 0, 8);
}
constexpr bool is_str(const_str s, int i)
{
return is_equ_n(s, i, "<str>", 0, 5);
}
//constexpr ? parse_route(StrWrap s)
//{
//return
//}
constexpr bool is_path(const_str s, int i)
{
return is_equ_n(s, i, "<path>", 0, 6);
}
template <typename ...Args>
struct Caller
{
template <typename F>
void operator()(F f, Args... args)
{
f(args...);
}
};
template <int N, typename ... Args> struct S;
template <int N, typename Arg, typename ... Args> struct S<N, Arg, Args...> {
static_assert(N <= 4+1, "too many routing arguments (maximum 5)");
template <typename T>
using push = typename std::conditional<(N>4), S<N, Arg, Args...>, S<N+1, Arg, Args..., T>>::type;
using pop = S<N-1, Args...>;
};
template <> struct S<0>
{
template <typename T>
using push = S<1, T>;
};
template <typename F, typename Set>
struct CallHelper;
template <typename F, int N, typename ...Args>
struct CallHelper<F, S<N, Args...>>
{
template <typename F1, typename ...Args1, typename =
decltype(std::declval<F1>()(std::declval<Args1>()...))
>
static char __test(int);
template <typename ...>
static int __test(...);
static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
};
static_assert(CallHelper<void(), S<0>>::value, "");
static_assert(CallHelper<void(int), S<1, int>>::value, "");
static_assert(!CallHelper<void(int), S<0>>::value, "");
static_assert(!CallHelper<void(int), S<2, int, int>>::value, "");
template <typename F,
typename Set = S<0>>
constexpr bool validate_helper(const_str rule, unsigned i=0)
{
return
i == rule.size()
? CallHelper<F, Set>::value :
is_int(rule, i)
? validate_helper<F, typename Set::template push<int>>(rule, find_closing_tag(rule, i+1)+1) :
is_float(rule, i)
? validate_helper<F, typename Set::template push<double>>(rule, find_closing_tag(rule, i+1)+1) :
is_str(rule, i)
? validate_helper<F, typename Set::template push<std::string>>(rule, find_closing_tag(rule, i+1)+1) :
is_path(rule, i)
? validate_helper<F, typename Set::template push<std::string>>(rule, find_closing_tag(rule, i+1)+1) :
validate_helper<F, Set>(rule, i+1)
;
}
static_assert(validate_helper<void()>("/"),"");
static_assert(validate_helper<void(int)>("/<int>"),"");
static_assert(!validate_helper<void()>("/<int>"),"");
}
class Router
{
public:
constexpr Router(black_magic::StrWrap s)
constexpr Router(black_magic::const_str rule) : rule(rule)
{
}
template <typename F>
constexpr bool validate() const
{
return black_magic::validate_helper<F>(rule);
}
private:
black_magic::const_str rule;
};
}

View File

@ -5,23 +5,36 @@
using namespace flask;
using namespace flask::black_magic;
template <int N> struct T{};
template <int N> struct ThrowTest{};
int main()
{
try
{
throw T<is_int("1<int>22",0)>();
throw ThrowTest<is_int("1<int>22",0)>();
}
catch(T<0>)
catch(ThrowTest<0>)
{
}
try
{
throw T<is_int("1<int>22",1)>();
throw ThrowTest<is_int("1<int>22",1)>();
}
catch(T<1>)
catch(ThrowTest<1>)
{
}
{
constexpr Router r = Router("/");
static_assert(r.validate<void()>(), "Good handler");
static_assert(!r.validate<void(int)>(), "Bad handler - no int argument");
}
{
constexpr Router r = Router("/blog/<int>");
static_assert(!r.validate<void()>(), "Bad handler - need argument");
static_assert(r.validate<void(int)>(), "Good handler");
static_assert(!r.validate<void(std::string)>(), "Bad handler - int is not convertible to std::string");
static_assert(r.validate<void(double)>(), "Acceptable handler - int will be converted to double");
}
}

View File

@ -14,37 +14,36 @@ namespace flask
}
// from http://akrzemi1.wordpress.com/2011/05/11/parsing-strings-at-compile-time-part-i/
class StrWrap
class const_str
{
const char * const begin_;
unsigned size_;
public:
template< unsigned N >
constexpr StrWrap( const char(&arr)[N] ) : begin_(arr), size_(N - 1) {
constexpr const_str( const char(&arr)[N] ) : begin_(arr), size_(N - 1) {
static_assert( N >= 1, "not a string literal");
}
constexpr char operator[]( unsigned i ) {
constexpr char operator[]( unsigned i ) const {
return requires_in_range(i, size_), begin_[i];
}
constexpr operator const char *() {
constexpr operator const char *() const {
return begin_;
}
constexpr unsigned size() {
constexpr unsigned size() const {
return size_;
}
};
constexpr int find_closing_tag(StrWrap s, std::size_t p)
constexpr unsigned find_closing_tag(const_str s, unsigned p)
{
return s[p] == '>' ? p : find_closing_tag(s, p+1);
}
constexpr int count(StrWrap s, int i=0)
constexpr int count(const_str s, int i=0)
{
return i == s.size() ? 0 : s[i] == '<' ? 1+count(s,i+1) : count(s,i+1);
}