From 738d5d47b55fa612842060dfa4924abf476c0726 Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Tue, 4 Nov 2014 17:12:52 +0000 Subject: Responses constructed from json::wvalue now automatically set the appropriate Content-Type header --- amalgamate/crow_all.h | 5049 +++++++++++++++++++++++++------------------------ 1 file changed, 2533 insertions(+), 2516 deletions(-) (limited to 'amalgamate') diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 2c7613d..2294438 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -1,483 +1,937 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include -// ---------------------------------------------------------------------------- -// qs_parse (modified) -// https://github.com/bartgrantham/qs_parse -// ---------------------------------------------------------------------------- -/* Similar to strncmp, but handles URL-encoding for either string */ -int qs_strncmp(const char * s, const char * qs, size_t n); +namespace crow +{ + namespace black_magic + { + struct OutOfRange + { + OutOfRange(unsigned pos, unsigned length) {} + }; + constexpr unsigned requires_in_range( unsigned i, unsigned len ) + { + return i >= len ? throw OutOfRange(i, len) : i; + } + class const_str + { + const char * const begin_; + unsigned size_; -/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. - * Also decodes the value portion of the k/v pair *in-place*. In a future - * enhancement it will also have a compile-time option of sorting qs_kv - * alphabetically by key. */ -int qs_parse(char * qs, char * qs_kv[], int qs_kv_size); + public: + template< unsigned N > + 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 ) const { + return requires_in_range(i, size_), begin_[i]; + } + constexpr operator const char *() const { + return begin_; + } -/* Used by qs_parse to decode the value portion of a k/v pair */ -int qs_decode(char * qs); + constexpr const char* begin() const { return begin_; } + constexpr const char* end() const { return begin_ + size_; } + constexpr unsigned size() const { + return size_; + } + }; -/* Looks up the value according to the key on a pre-processed query string - * A future enhancement will be a compile-time option to look up the key - * in a pre-sorted qs_kv array via a binary search. */ -//char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); - char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth); + constexpr unsigned find_closing_tag(const_str s, unsigned p) + { + return s[p] == '>' ? p : find_closing_tag(s, p+1); + } -/* Non-destructive lookup of value, based on key. User provides the - * destinaton string and length. */ -char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len); + constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) + { + return + i == s.size() + ? f == 0 : + f < 0 || f >= 2 + ? false : + s[i] == '<' + ? is_valid(s, i+1, f+1) : + s[i] == '>' + ? is_valid(s, i+1, f-1) : + is_valid(s, i+1, f); + } -// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled -#undef _qsSORTING + constexpr bool is_equ_p(const char* a, const char* b, unsigned n) + { + return + *a == 0 && *b == 0 && n == 0 + ? true : + (*a == 0 || *b == 0) + ? false : + n == 0 + ? true : + *a != *b + ? false : + is_equ_p(a+1, b+1, n-1); + } -// isxdigit _is_ available in , but let's avoid another header instead -#define CROW_QS_ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0) -#define CROW_QS_HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) -#define CROW_QS_ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) + constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) + { + 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); + } -inline int qs_strncmp(const char * s, const char * qs, size_t n) -{ - int i=0; - unsigned char u1, u2, unyb, lnyb; + constexpr bool is_int(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5); + } - while(n-- > 0) - { - u1 = (unsigned char) *s++; - u2 = (unsigned char) *qs++; + constexpr bool is_uint(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } - if ( ! CROW_QS_ISQSCHR(u1) ) { u1 = '\0'; } - if ( ! CROW_QS_ISQSCHR(u2) ) { u2 = '\0'; } + constexpr bool is_float(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 7) || + is_equ_n(s, i, "", 0, 8); + } - if ( u1 == '+' ) { u1 = ' '; } - if ( u1 == '%' ) // easier/safer than scanf + constexpr bool is_str(const_str s, unsigned i) { - unyb = (unsigned char) *s++; - lnyb = (unsigned char) *s++; - if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) - u1 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); - else - u1 = '\0'; + return is_equ_n(s, i, "", 0, 5) || + is_equ_n(s, i, "", 0, 8); } - if ( u2 == '+' ) { u2 = ' '; } - if ( u2 == '%' ) // easier/safer than scanf + constexpr bool is_path(const_str s, unsigned i) { - unyb = (unsigned char) *qs++; - lnyb = (unsigned char) *qs++; - if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) - u2 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); - else - u2 = '\0'; + return is_equ_n(s, i, "", 0, 6); } - if ( u1 != u2 ) - return u1 - u2; - if ( u1 == '\0' ) - return 0; - i++; - } - if ( CROW_QS_ISQSCHR(*qs) ) - return -1; - else - return 0; -} + constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) + { + return + p == s.size() + ? 0 : + s[p] == '<' ? ( + is_int(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : + is_uint(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : + is_float(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : + is_str(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : + is_path(s, p) + ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : + throw std::runtime_error("invalid parameter type") + ) : + get_parameter_tag(s, p+1); + } + template + struct S + { + template + using push = S; + template + using push_back = S; + template class U> + using rebind = U; + }; +template + struct CallHelper; + template + struct CallHelper> + { + template ()(std::declval()...)) + > + static char __test(int); -inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) -{ - int i, j; - char * substr_ptr; + template + static int __test(...); - for(i=0; i(0)) == sizeof(char); + }; - // find the beginning of the k/v substrings - if ( (substr_ptr = strchr(qs, '?')) != NULL ) - substr_ptr++; - else - substr_ptr = qs; - i=0; - while(i means x iterations of this loop -> means *x+1* k/v pairs + template + struct single_tag_to_type + { + }; - // we only decode the values in place, the keys could have '='s in them - // which will hose our ability to distinguish keys from values later - for(j=0; j + struct single_tag_to_type<1> + { + using type = int64_t; + }; -#ifdef _qsSORTING -// TODO: qsort qs_kv, using qs_strncmp() for the comparison -#endif + template <> + struct single_tag_to_type<2> + { + using type = uint64_t; + }; - return i; -} - - -inline int qs_decode(char * qs) -{ - int i=0, j=0; + template <> + struct single_tag_to_type<3> + { + using type = double; + }; - while( CROW_QS_ISQSCHR(qs[j]) ) - { - if ( qs[j] == '+' ) { qs[i] = ' '; } - else if ( qs[j] == '%' ) // easier/safer than scanf + template <> + struct single_tag_to_type<4> { - if ( ! CROW_QS_ISHEX(qs[j+1]) || ! CROW_QS_ISHEX(qs[j+2]) ) - { - qs[i] = '\0'; - return i; - } - qs[i] = (CROW_QS_HEX2DEC(qs[j+1]) * 16) + CROW_QS_HEX2DEC(qs[j+2]); - j+=2; - } - else + using type = std::string; + }; + + template <> + struct single_tag_to_type<5> { - qs[i] = qs[j]; - } - i++; j++; - } - qs[i] = '\0'; + using type = std::string; + }; - return i; -} + template + struct arguments + { + using subarguments = typename arguments::type; + using type = + typename subarguments::template push::type>; + }; -inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = 0) -{ - int i; - size_t key_len, skip; + template <> + struct arguments<0> + { + using type = S<>; + }; - key_len = strlen(key); + template + struct last_element_type + { + using type = typename std::tuple_element>::type; + }; -#ifdef _qsSORTING -// TODO: binary search for key in the sorted qs_kv -#else // _qsSORTING - for(i=0; i using Invoke = typename T::type; -inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) -{ - size_t i, key_len; - const char * tmp; + template struct seq{ using type = seq; }; - // find the beginning of the k/v substrings - if ( (tmp = strchr(qs, '?')) != NULL ) - qs = tmp + 1; + template struct concat; - key_len = strlen(key); - while(qs[0] != '#' && qs[0] != '\0') - { - if ( qs_strncmp(key, qs, key_len) == 0 ) - break; - qs += strcspn(qs, "&") + 1; - } + template + struct concat, seq> + : seq{}; - if ( qs[0] == '\0' ) return NULL; + template + using Concat = Invoke>; - qs += strcspn(qs, "=&#"); - if ( qs[0] == '=' ) - { - qs++; - i = strcspn(qs, "&=#"); - strncpy(val, qs, (val_len-1)<(i+1) ? (val_len-1) : (i+1)); - qs_decode(val); - } - else - { - if ( val_len > 0 ) - val[0] = '\0'; - } + template struct gen_seq; + template using GenSeq = Invoke>; - return val; -} -// ---------------------------------------------------------------------------- + template + struct gen_seq : Concat, GenSeq>{}; + template<> struct gen_seq<0> : seq<>{}; + template<> struct gen_seq<1> : seq<0>{}; -namespace crow -{ - class query_string - { - public: - static const int MAX_KEY_VALUE_PAIRS_COUNT = 256; + template + struct pop_back_helper; - query_string() + template + struct pop_back_helper, Tuple> { + template