From 15d377907fd8b63e2d8474dfeeeb1765fd8b729d Mon Sep 17 00:00:00 2001 From: Rasie1 Date: Thu, 16 Mar 2017 19:27:34 +0300 Subject: Update amalgamate --- amalgamate/crow_all.h | 11253 ++++++++++++++++++++++++------------------------ 1 file changed, 5652 insertions(+), 5601 deletions(-) diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 6ffbe66..7f2dee1 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -1,40 +1,3 @@ -#pragma once - -#include -#include -#include - -namespace crow -{ - struct ci_hash - { - size_t operator()(const std::string& key) const - { - std::size_t seed = 0; - std::locale locale; - - for(auto c : key) - { - boost::hash_combine(seed, std::toupper(c, locale)); - } - - return seed; - } - }; - - struct ci_key_eq - { - bool operator()(const std::string& l, const std::string& r) const - { - return boost::iequals(l, r); - } - }; - - using ci_map = std::unordered_multimap; -} - - - /* * * TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based @@ -235,6339 +198,6254 @@ namespace sha1 #pragma once +// settings for crow +// TODO - replace with runtime config. libucl? -#include -#include -#include -#include -#include +/* #ifdef - enables debug mode */ +#define CROW_ENABLE_DEBUG -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); +/* #ifdef - enables logging */ +#define CROW_ENABLE_LOGGING +/* #ifdef - enables ssl */ +//#define CROW_ENABLE_SSL -/* 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); +/* #define - specifies log level */ +/* + Debug = 0 + Info = 1 + Warning = 2 + Error = 3 + Critical = 4 + default to INFO +*/ +#define CROW_LOG_LEVEL 1 -/* Used by qs_parse to decode the value portion of a k/v pair */ -int qs_decode(char * qs); +// compiler flags +#if __cplusplus >= 201402L +#define CROW_CAN_USE_CPP14 +#endif -/* 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); +#if defined(_MSC_VER) +#if _MSC_VER < 1900 +#define CROW_MSVC_WORKAROUND +#define constexpr const +#define noexcept throw() +#endif +#endif -/* 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 +#pragma once -// 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) +#include +#include +#include +#include +#include +#include +#include -inline int qs_strncmp(const char * s, const char * qs, size_t n) -{ - int i=0; - unsigned char u1, u2, unyb, lnyb; - while(n-- > 0) - { - 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 +namespace crow +{ + namespace black_magic + { +#ifndef CROW_MSVC_WORKAROUND + struct OutOfRange { - 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'; - } - - if ( u2 == '+' ) { u2 = ' '; } - if ( u2 == '%' ) // easier/safer than scanf + OutOfRange(unsigned /*pos*/, unsigned /*length*/) {} + }; + constexpr unsigned requires_in_range( unsigned i, unsigned len ) { - 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 i >= len ? throw OutOfRange(i, len) : i; } - if ( u1 != u2 ) - return u1 - u2; - if ( u1 == '\0' ) - return 0; - i++; - } - if ( CROW_QS_ISQSCHR(*qs) ) - return -1; - else - return 0; -} - - -inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) -{ - int i, j; - char * substr_ptr; - - for(i=0; i means x iterations of this loop -> means *x+1* k/v pairs - - // 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 + 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]; + } - return i; -} + 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_decode(char * qs) -{ - int i=0, j=0; + constexpr unsigned size() const { + return size_; + } + }; - while( CROW_QS_ISQSCHR(qs[j]) ) - { - if ( qs[j] == '+' ) { qs[i] = ' '; } - else if ( qs[j] == '%' ) // easier/safer than scanf + constexpr unsigned find_closing_tag(const_str s, unsigned p) { - 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; + return s[p] == '>' ? p : find_closing_tag(s, p+1); } - else + + constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) { - qs[i] = qs[j]; + 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++; j++; - } - qs[i] = '\0'; - - 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 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); } - query_string(const query_string& qs) - : url_(qs.url_) + constexpr bool is_int(const_str s, unsigned i) { - for(auto p:qs.key_value_pairs_) - { - key_value_pairs_.push_back((char*)(p-qs.url_.c_str()+url_.c_str())); - } + return is_equ_n(s, i, "", 0, 5); } - query_string& operator = (const query_string& qs) + constexpr bool is_uint(const_str s, unsigned i) { - 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; + return is_equ_n(s, i, "", 0, 6); } - query_string& operator = (query_string&& qs) + constexpr bool is_float(const_str s, unsigned i) { - 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; + return is_equ_n(s, i, "", 0, 7) || + is_equ_n(s, i, "", 0, 8); } - - query_string(std::string url) - : url_(std::move(url)) + constexpr bool is_str(const_str s, unsigned i) { - if (url_.empty()) - return; - - 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); + return is_equ_n(s, i, "", 0, 5) || + is_equ_n(s, i, "", 0, 8); } - void clear() + constexpr bool is_path(const_str s, unsigned i) { - key_value_pairs_.clear(); - url_.clear(); + return is_equ_n(s, 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; - friend std::ostream& operator<<(std::ostream& os, const query_string& qs) + template <> + struct compute_parameter_tag_from_args_list<> { - 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; + 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; + }; - char* get (const std::string& name) const + static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) { - char* ret = qs_k2v(name.c_str(), key_value_pairs_.data(), key_value_pairs_.size()); - return ret; + 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); } - std::vector get_list (const std::string& name) const + static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) { - 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; + return + s[p] == 0 + ? throw std::runtime_error("unmatched tag <") : + s[p] == '>' + ? p : find_closing_tag_runtime(s, p + 1); + } + + static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) + { + 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); + } +#ifndef CROW_MSVC_WORKAROUND + 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); } - - - private: - std::string url_; - std::vector key_value_pairs_; - }; - -} // end namespace - - - -/* merged revision: 5b951d74bd66ec9d38448e0a85b1cf8b85d97db3 */ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef CROW_http_parser_h -#define CROW_http_parser_h -#ifdef __cplusplus -extern "C" { #endif -/* Also update SONAME in the Makefile whenever you change these. */ -#define CROW_HTTP_PARSER_VERSION_MAJOR 2 -#define CROW_HTTP_PARSER_VERSION_MINOR 3 -#define CROW_HTTP_PARSER_VERSION_PATCH 0 + 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); -#include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) -#include -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif + template + static int __test(...); -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef CROW_HTTP_PARSER_STRICT -# define CROW_HTTP_PARSER_STRICT 1 -#endif + static constexpr bool value = sizeof(__test(0)) == sizeof(char); + }; -/* Maximium header size allowed. If the macro is not defined - * before including this header then the default is used. To - * change the maximum header size, define the macro in the build - * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove - * the effective limit on the size of the header, define the macro - * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) - */ -#ifndef CROW_HTTP_MAX_HEADER_SIZE -# define CROW_HTTP_MAX_HEADER_SIZE (80*1024) -#endif -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; + template + struct single_tag_to_type + { + }; + template <> + struct single_tag_to_type<1> + { + using type = int64_t; + }; -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * http_data_cb does not return data chunks. It will be call arbitrarally - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); + template <> + struct single_tag_to_type<2> + { + using type = uint64_t; + }; + template <> + struct single_tag_to_type<3> + { + using type = double; + }; -/* Request Methods */ -#define CROW_HTTP_METHOD_MAP(CROW_XX) \ - CROW_XX(0, DELETE, DELETE) \ - CROW_XX(1, GET, GET) \ - CROW_XX(2, HEAD, HEAD) \ - CROW_XX(3, POST, POST) \ - CROW_XX(4, PUT, PUT) \ - /* pathological */ \ - CROW_XX(5, CONNECT, CONNECT) \ - CROW_XX(6, OPTIONS, OPTIONS) \ - CROW_XX(7, TRACE, TRACE) \ - /* webdav */ \ - CROW_XX(8, COPY, COPY) \ - CROW_XX(9, LOCK, LOCK) \ - CROW_XX(10, MKCOL, MKCOL) \ - CROW_XX(11, MOVE, MOVE) \ - CROW_XX(12, PROPFIND, PROPFIND) \ - CROW_XX(13, PROPPATCH, PROPPATCH) \ - CROW_XX(14, SEARCH, SEARCH) \ - CROW_XX(15, UNLOCK, UNLOCK) \ - /* subversion */ \ - CROW_XX(16, REPORT, REPORT) \ - CROW_XX(17, MKACTIVITY, MKACTIVITY) \ - CROW_XX(18, CHECKOUT, CHECKOUT) \ - CROW_XX(19, MERGE, MERGE) \ - /* upnp */ \ - CROW_XX(20, MSEARCH, M-SEARCH) \ - CROW_XX(21, NOTIFY, NOTIFY) \ - CROW_XX(22, SUBSCRIBE, SUBSCRIBE) \ - CROW_XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - CROW_XX(24, PATCH, PATCH) \ - CROW_XX(25, PURGE, PURGE) \ - /* CalDAV */ \ - CROW_XX(26, MKCALENDAR, MKCALENDAR) \ + template <> + struct single_tag_to_type<4> + { + using type = std::string; + }; -enum http_method - { -#define CROW_XX(num, name, string) HTTP_##name = num, - CROW_HTTP_METHOD_MAP(CROW_XX) -#undef CROW_XX - }; + template <> + struct single_tag_to_type<5> + { + using type = std::string; + }; -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; + template + struct arguments + { + using subarguments = typename arguments::type; + using type = + typename subarguments::template push::type>; + }; + template <> + struct arguments<0> + { + using type = S<>; + }; -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; + template + struct last_element_type + { + using type = typename std::tuple_element>::type; + }; -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define CROW_HTTP_ERRNO_MAP(CROW_XX) \ - /* No error */ \ - CROW_XX(OK, "success") \ - \ - /* Callback-related errors */ \ - CROW_XX(CB_message_begin, "the on_message_begin callback failed") \ - CROW_XX(CB_url, "the on_url callback failed") \ - CROW_XX(CB_header_field, "the on_header_field callback failed") \ - CROW_XX(CB_header_value, "the on_header_value callback failed") \ - CROW_XX(CB_headers_complete, "the on_headers_complete callback failed") \ - CROW_XX(CB_body, "the on_body callback failed") \ - CROW_XX(CB_message_complete, "the on_message_complete callback failed") \ - CROW_XX(CB_status, "the on_status callback failed") \ - \ - /* Parsing-related errors */ \ - CROW_XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - CROW_XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - CROW_XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - CROW_XX(INVALID_VERSION, "invalid HTTP version") \ - CROW_XX(INVALID_STATUS, "invalid HTTP status code") \ - CROW_XX(INVALID_METHOD, "invalid HTTP method") \ - CROW_XX(INVALID_URL, "invalid URL") \ - CROW_XX(INVALID_HOST, "invalid host") \ - CROW_XX(INVALID_PORT, "invalid port") \ - CROW_XX(INVALID_PATH, "invalid path") \ - CROW_XX(INVALID_QUERY_STRING, "invalid query string") \ - CROW_XX(INVALID_FRAGMENT, "invalid fragment") \ - CROW_XX(LF_EXPECTED, "CROW_LF character expected") \ - CROW_XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - CROW_XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - CROW_XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - CROW_XX(INVALID_CONSTANT, "invalid constant string") \ - CROW_XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - CROW_XX(STRICT, "strict mode assertion failed") \ - CROW_XX(PAUSED, "parser is paused") \ - CROW_XX(UNKNOWN, "an unknown error occurred") + template <> + struct last_element_type<> + { + }; -/* Define HPE_* values for each errno value above */ -#define CROW_HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - CROW_HTTP_ERRNO_MAP(CROW_HTTP_ERRNO_GEN) -}; -#undef CROW_HTTP_ERRNO_GEN + // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth + template using Invoke = typename T::type; + template struct seq{ using type = seq; }; -/* Get an http_errno value from an http_parser */ -#define CROW_HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) + template struct concat; + template + struct concat, seq> + : seq{}; -struct http_parser { - /** PRIVATE **/ - unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned int state : 8; /* enum state from http_parser.c */ - unsigned int header_state : 8; /* enum header_state from http_parser.c */ - unsigned int index : 8; /* index into current matcher */ + template + using Concat = Invoke>; - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ + template struct gen_seq; + template using GenSeq = Invoke>; - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned int status_code : 16; /* responses only */ - unsigned int method : 8; /* requests only */ - unsigned int http_errno : 7; + template + struct gen_seq : Concat, GenSeq>{}; - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned int upgrade : 1; + template<> struct gen_seq<0> : seq<>{}; + template<> struct gen_seq<1> : seq<0>{}; - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; + template + struct pop_back_helper; + template + struct pop_back_helper, Tuple> + { + template