aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--routing.h110
-rw-r--r--unittest.cpp23
-rw-r--r--utility.h15
3 files changed, 126 insertions, 22 deletions
diff --git a/routing.h b/routing.h
index ca9c0ec..a150a4e 100644
--- a/routing.h
+++ b/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;
};
}
diff --git a/unittest.cpp b/unittest.cpp
index 0cea0c7..66c58a0 100644
--- a/unittest.cpp
+++ b/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");
+ }
}
diff --git a/utility.h b/utility.h
index c8575d3..8499532 100644
--- a/utility.h
+++ b/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);
}