mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
routing class working version
This commit is contained in:
parent
5e5d696884
commit
d533a619c9
110
routing.h
110
routing.h
@ -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;
|
||||
};
|
||||
}
|
||||
|
23
unittest.cpp
23
unittest.cpp
@ -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");
|
||||
}
|
||||
}
|
||||
|
15
utility.h
15
utility.h
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user