From da4bb3aeab4112071b25e53142cb286b10b91b23 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Mon, 23 May 2016 22:04:33 +0900 Subject: update amalgamate --- amalgamate/crow_all.h | 10391 ++++++++++++++++++++++++------------------------ 1 file changed, 5200 insertions(+), 5191 deletions(-) diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 63b4dd0..74676ef 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -1,5845 +1,5884 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace crow +// ---------------------------------------------------------------------------- +// 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); + + +/* 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); + + +/* Used by qs_parse to decode the value portion of a k/v pair */ +int qs_decode(char * qs); + + +/* 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); + + +/* 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); + +// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled +#undef _qsSORTING + +// 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) + +inline int qs_strncmp(const char * s, const char * qs, size_t n) { - namespace black_magic + int i=0; + unsigned char u1, u2, unyb, lnyb; + + while(n-- > 0) { -#ifndef CROW_MSVC_WORKAROUND - struct OutOfRange - { - OutOfRange(unsigned pos, unsigned length) {} - }; - constexpr unsigned requires_in_range( unsigned i, unsigned len ) + u1 = (unsigned char) *s++; + u2 = (unsigned char) *qs++; + + if ( ! CROW_QS_ISQSCHR(u1) ) { u1 = '\0'; } + if ( ! CROW_QS_ISQSCHR(u2) ) { u2 = '\0'; } + + if ( u1 == '+' ) { u1 = ' '; } + if ( u1 == '%' ) // easier/safer than scanf { - return i >= len ? throw OutOfRange(i, len) : 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'; } - class const_str + if ( u2 == '+' ) { u2 = ' '; } + if ( u2 == '%' ) // easier/safer than scanf { - const char * const begin_; - unsigned size_; + 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'; + } - 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]; - } + if ( u1 != u2 ) + return u1 - u2; + if ( u1 == '\0' ) + return 0; + i++; + } + if ( CROW_QS_ISQSCHR(*qs) ) + return -1; + else + return 0; +} - constexpr operator const char *() const { - return begin_; - } - constexpr const char* begin() const { return begin_; } - constexpr const char* end() const { return begin_ + size_; } +inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +{ + int i, j; + char * substr_ptr; - constexpr unsigned size() const { - return size_; - } - }; + for(i=0; i' ? p : find_closing_tag(s, p+1); - } + // find the beginning of the k/v substrings or the fragment + substr_ptr = qs + strcspn(qs, "?#"); + if (substr_ptr[0] != '\0') + substr_ptr++; + else + return 0; // no query or fragment - 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); - } + i=0; + while(i means x iterations of this loop -> means *x+1* k/v pairs - 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); - } + // 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 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); - } +#ifdef _qsSORTING +// TODO: qsort qs_kv, using qs_strncmp() for the comparison +#endif - constexpr bool is_int(const_str s, unsigned i) - { - return is_equ_n(s, i, "", 0, 5); - } + return i; +} - constexpr bool is_uint(const_str s, unsigned i) + +inline int qs_decode(char * qs) +{ + int i=0, j=0; + + while( CROW_QS_ISQSCHR(qs[j]) ) + { + if ( qs[j] == '+' ) { qs[i] = ' '; } + else if ( qs[j] == '%' ) // easier/safer than scanf { - return is_equ_n(s, i, "", 0, 6); + 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; } - - constexpr bool is_float(const_str s, unsigned i) + else { - return is_equ_n(s, i, "", 0, 7) || - is_equ_n(s, i, "", 0, 8); + qs[i] = qs[j]; } + i++; j++; + } + qs[i] = '\0'; - constexpr bool is_str(const_str s, unsigned i) + return i; +} + + +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; + + key_len = strlen(key); + +#ifdef _qsSORTING +// TODO: binary search for key in the sorted qs_kv +#else // _qsSORTING + for(i=0; i", 0, 6); - } -#endif - template - struct parameter_tag - { - static const int value = 0; - }; -#define CROW_INTERNAL_PARAMETER_TAG(t, i) \ -template <> \ -struct parameter_tag \ -{ \ - static const int value = i; \ -}; - CROW_INTERNAL_PARAMETER_TAG(int, 1); - CROW_INTERNAL_PARAMETER_TAG(char, 1); - CROW_INTERNAL_PARAMETER_TAG(short, 1); - CROW_INTERNAL_PARAMETER_TAG(long, 1); - CROW_INTERNAL_PARAMETER_TAG(long long, 1); - CROW_INTERNAL_PARAMETER_TAG(unsigned int, 2); - CROW_INTERNAL_PARAMETER_TAG(unsigned char, 2); - CROW_INTERNAL_PARAMETER_TAG(unsigned short, 2); - CROW_INTERNAL_PARAMETER_TAG(unsigned long, 2); - CROW_INTERNAL_PARAMETER_TAG(unsigned long long, 2); - CROW_INTERNAL_PARAMETER_TAG(double, 3); - CROW_INTERNAL_PARAMETER_TAG(std::string, 4); -#undef CROW_INTERNAL_PARAMETER_TAG - template - struct compute_parameter_tag_from_args_list; + return NULL; +} - template <> - struct compute_parameter_tag_from_args_list<> - { - static const int value = 0; - }; - template - struct compute_parameter_tag_from_args_list - { - static const int sub_value = - compute_parameter_tag_from_args_list::value; - static const int value = - parameter_tag::type>::value - ? sub_value* 6 + parameter_tag::type>::value - : sub_value; - }; +inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) +{ + size_t i, key_len; + const char * tmp; - static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) + // find the beginning of the k/v substrings + if ( (tmp = strchr(qs, '?')) != NULL ) + qs = tmp + 1; + + key_len = strlen(key); + while(qs[0] != '#' && qs[0] != '\0') + { + if ( qs_strncmp(key, qs, key_len) == 0 ) + break; + qs += strcspn(qs, "&") + 1; + } + + if ( qs[0] == '\0' ) return NULL; + + 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'; + } + + return val; +} +// ---------------------------------------------------------------------------- + + +namespace crow +{ + class query_string + { + public: + static const int MAX_KEY_VALUE_PAIRS_COUNT = 256; + + query_string() { - if (a == 0) - return b == 0; - if (b == 0) - return a == 0; - int sa = a%6; - int sb = a%6; - if (sa == 5) sa = 4; - if (sb == 5) sb = 4; - if (sa != sb) - return false; - return is_parameter_tag_compatible(a/6, b/6); + } - static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) + query_string(const query_string& qs) + : url_(qs.url_) { - return - s[p] == 0 - ? throw std::runtime_error("unmatched tag <") : - s[p] == '>' - ? p : find_closing_tag_runtime(s, p + 1); + for(auto p:qs.key_value_pairs_) + { + key_value_pairs_.push_back((char*)(p-qs.url_.c_str()+url_.c_str())); + } } - - static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) + + query_string& operator = (const query_string& qs) { - return - s[p] == 0 - ? 0 : - s[p] == '<' ? ( - std::strncmp(s+p, "", 5) == 0 - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : - std::strncmp(s+p, "", 6) == 0 - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : - (std::strncmp(s+p, "", 7) == 0 || - std::strncmp(s+p, "", 8) == 0) - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : - (std::strncmp(s+p, "", 5) == 0 || - std::strncmp(s+p, "", 8) == 0) - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : - std::strncmp(s+p, "", 6) == 0 - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : - throw std::runtime_error("invalid parameter type") - ) : - get_parameter_tag_runtime(s, p+1); + url_ = qs.url_; + key_value_pairs_.clear(); + for(auto p:qs.key_value_pairs_) + { + key_value_pairs_.push_back((char*)(p-qs.url_.c_str()+url_.c_str())); + } + return *this; } -#ifndef CROW_MSVC_WORKAROUND - constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) + + query_string& operator = (query_string&& qs) { - 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); + key_value_pairs_ = std::move(qs.key_value_pairs_); + char* old_data = (char*)qs.url_.c_str(); + url_ = std::move(qs.url_); + for(auto& p:key_value_pairs_) + { + p += (char*)url_.c_str() - old_data; + } + return *this; } -#endif - 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); - template - static int __test(...); + query_string(std::string url) + : url_(std::move(url)) + { + if (url_.empty()) + return; - static constexpr bool value = sizeof(__test(0)) == sizeof(char); - }; + key_value_pairs_.resize(MAX_KEY_VALUE_PAIRS_COUNT); + int count = qs_parse(&url_[0], &key_value_pairs_[0], MAX_KEY_VALUE_PAIRS_COUNT); + key_value_pairs_.resize(count); + } - template - struct single_tag_to_type + void clear() { - }; + key_value_pairs_.clear(); + url_.clear(); + } - template <> - struct single_tag_to_type<1> + friend std::ostream& operator<<(std::ostream& os, const query_string& qs) { - using type = int64_t; - }; + os << "[ "; + for(size_t i = 0; i < qs.key_value_pairs_.size(); ++i) { + if (i) + os << ", "; + os << qs.key_value_pairs_[i]; + } + os << " ]"; + return os; - template <> - struct single_tag_to_type<2> - { - using type = uint64_t; - }; + } - template <> - struct single_tag_to_type<3> + char* get (const std::string& name) const { - using type = double; - }; + char* ret = qs_k2v(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size()); + return ret; + } - template <> - struct single_tag_to_type<4> + std::vector get_list (const std::string& name) const { - using type = std::string; - }; - - template <> - struct single_tag_to_type<5> - { - using type = std::string; - }; - - - template - struct arguments - { - using subarguments = typename arguments::type; - using type = - typename subarguments::template push::type>; - }; - - template <> - struct arguments<0> - { - using type = S<>; - }; - - template - struct last_element_type - { - using type = typename std::tuple_element>::type; - }; + std::vector ret; + std::string plus = name + "[]"; + char* element = nullptr; + int count = 0; + while(1) + { + element = qs_k2v(plus.c_str(), key_value_pairs_.data(), key_value_pairs_.size(), count++); + if (!element) + break; + ret.push_back(element); + } + return ret; + } - template <> - struct last_element_type<> - { - }; + private: + std::string url_; + std::vector key_value_pairs_; + }; - // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth - template using Invoke = typename T::type; +} // end namespace - template struct seq{ using type = seq; }; - template struct concat; - template - struct concat, seq> - : seq{}; +#pragma once - template - using Concat = Invoke>; +//#define CROW_JSON_NO_ERROR_CHECK - template struct gen_seq; - template using GenSeq = Invoke>; +#include +#include +#include +#include +#include +#include +#include +#include +#include - template - struct gen_seq : Concat, GenSeq>{}; +#if defined(__GNUG__) || defined(__clang__) +#define crow_json_likely(x) __builtin_expect(x, 1) +#define crow_json_unlikely(x) __builtin_expect(x, 0) +#else +#define crow_json_likely(x) x +#define crow_json_unlikely(x) x +#endif - template<> struct gen_seq<0> : seq<>{}; - template<> struct gen_seq<1> : seq<0>{}; - template - struct pop_back_helper; +namespace crow +{ + namespace mustache + { + class template_t; + } - template - struct pop_back_helper, Tuple> + namespace json + { + inline void escape(const std::string& str, std::string& ret) { - template