From acf686d3dd3e7ecde6527432fe3090a94929ed14 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Wed, 27 May 2015 14:49:40 -0400 Subject: update amalgate --- amalgamate/crow_all.h | 9627 +++++++++++++++++++++++++------------------------ 1 file changed, 4822 insertions(+), 4805 deletions(-) (limited to 'amalgamate/crow_all.h') diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 98d47e9..e066d97 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -99,11 +99,12 @@ inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) for(i=0; i -#include -#include -#include -#include -#include -#include -#include -#include - -#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 - +#include +#include +#include +#include +#include +#include namespace crow { - namespace mustache - { - class template_t; - } - - namespace json + namespace black_magic { - inline void escape(const std::string& str, std::string& ret) +#ifndef CROW_MSVC_WORKAROUND + struct OutOfRange { - ret.reserve(ret.size() + str.size()+str.size()/4); - for(char c:str) - { - switch(c) - { - case '"': ret += "\\\""; break; - case '\\': ret += "\\\\"; break; - case '\n': ret += "\\n"; break; - case '\b': ret += "\\b"; break; - case '\f': ret += "\\f"; break; - case '\r': ret += "\\r"; break; - case '\t': ret += "\\t"; break; - default: - if (0 <= c && c < 0x20) - { - ret += "\\u00"; - auto to_hex = [](char c) - { - c = c&0xf; - if (c < 10) - return '0' + c; - return 'a'+c-10; - }; - ret += to_hex(c/16); - ret += to_hex(c%16); - } - else - ret += c; - break; - } - } - } - inline std::string escape(const std::string& str) + OutOfRange(unsigned pos, unsigned length) {} + }; + constexpr unsigned requires_in_range( unsigned i, unsigned len ) { - std::string ret; - escape(str, ret); - return ret; + return i >= len ? throw OutOfRange(i, len) : i; } - enum class type : char - { - Null, - False, - True, - Number, - String, - List, - Object, - }; - - class rvalue; - rvalue load(const char* data, size_t size); - - namespace detail + class const_str { + const char * const begin_; + unsigned size_; - struct r_string - : boost::less_than_comparable, - boost::less_than_comparable, - boost::equality_comparable, - boost::equality_comparable - { - r_string() {}; - r_string(char* s, char* e) - : s_(s), e_(e) - {}; - ~r_string() - { - if (owned_) - delete[] s_; - } - - r_string(const r_string& r) - { - *this = r; - } - - r_string(r_string&& r) - { - *this = r; - } - - r_string& operator = (r_string&& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = r.owned_; - return *this; + 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]; + } - r_string& operator = (const r_string& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = 0; - return *this; - } + constexpr operator const char *() const { + return begin_; + } - operator std::string () const - { - return std::string(s_, e_); - } + constexpr const char* begin() const { return begin_; } + constexpr const char* end() const { return begin_ + size_; } + constexpr unsigned size() const { + return size_; + } + }; - const char* begin() const { return s_; } - const char* end() const { return e_; } - size_t size() const { return end() - begin(); } + constexpr unsigned find_closing_tag(const_str s, unsigned p) + { + return s[p] == '>' ? p : find_closing_tag(s, p+1); + } - using iterator = const char*; - using const_iterator = const char*; + 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); + } - char* s_; - mutable char* e_; - uint8_t owned_{0}; - friend std::ostream& operator << (std::ostream& os, const r_string& s) - { - os << (std::string)s; - return os; - } - private: - void force(char* s, uint32_t length) - { - s_ = s; - owned_ = 1; - } - friend rvalue crow::json::load(const char* data, size_t size); - }; + 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); + } - inline bool operator < (const r_string& l, const r_string& r) - { - return boost::lexicographical_compare(l,r); - } + 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 bool operator < (const r_string& l, const std::string& r) - { - return boost::lexicographical_compare(l,r); - } + constexpr bool is_int(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5); + } - inline bool operator > (const r_string& l, const std::string& r) - { - return boost::lexicographical_compare(r,l); - } + constexpr bool is_uint(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } - inline bool operator == (const r_string& l, const r_string& r) - { - return boost::equals(l,r); - } + constexpr bool is_float(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 7) || + is_equ_n(s, i, "", 0, 8); + } - inline bool operator == (const r_string& l, const std::string& r) - { - return boost::equals(l,r); - } + constexpr bool is_str(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5) || + is_equ_n(s, i, "", 0, 8); } - class rvalue + constexpr bool is_path(const_str s, unsigned i) { - static const int cached_bit = 2; - static const int error_bit = 4; - public: - rvalue() noexcept : option_{error_bit} - {} - rvalue(type t) noexcept - : lsize_{}, lremain_{}, t_{t} - {} - rvalue(type t, char* s, char* e) noexcept - : start_{s}, - end_{e}, - t_{t} - {} + 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; - rvalue(const rvalue& r) - : start_(r.start_), - end_(r.end_), - key_(r.key_), - t_(r.t_), - option_(r.option_) - { - copy_l(r); - } + template <> + struct compute_parameter_tag_from_args_list<> + { + static const int value = 0; + }; - rvalue(rvalue&& r) noexcept - { - *this = std::move(r); - } + 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; + }; - rvalue& operator = (const rvalue& r) - { - start_ = r.start_; - end_ = r.end_; - key_ = r.key_; - copy_l(r); - t_ = r.t_; - option_ = r.option_; - return *this; - } - rvalue& operator = (rvalue&& r) noexcept - { - start_ = r.start_; - end_ = r.end_; - key_ = std::move(r.key_); - l_ = std::move(r.l_); - lsize_ = r.lsize_; - lremain_ = r.lremain_; - t_ = r.t_; - option_ = r.option_; - return *this; - } + static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) + { + 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); + } - explicit operator bool() const noexcept - { - return (option_ & error_bit) == 0; - } + static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) + { + 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); + } +#endif - explicit operator int64_t() const - { - return i(); - } + 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); - explicit operator int() const - { - return (int)i(); - } + template + static int __test(...); - type t() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (option_ & error_bit) - { - throw std::runtime_error("invalid json object"); - } -#endif - return t_; - } + static constexpr bool value = sizeof(__test(0)) == sizeof(char); + }; - int64_t i() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Number) - throw std::runtime_error("value is not number"); -#endif - return boost::lexical_cast(start_, end_-start_); - } - double d() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Number) - throw std::runtime_error("value is not number"); -#endif - return boost::lexical_cast(start_, end_-start_); - } + template + struct single_tag_to_type + { + }; - bool b() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::True && t() != type::False) - throw std::runtime_error("value is not boolean"); -#endif - return t() == type::True; - } + template <> + struct single_tag_to_type<1> + { + using type = int64_t; + }; - void unescape() const - { - if (*(start_-1)) - { - char* head = start_; - char* tail = start_; - while(head != end_) - { - if (*head == '\\') - { - switch(*++head) - { - case '"': *tail++ = '"'; break; - case '\\': *tail++ = '\\'; break; - case '/': *tail++ = '/'; break; - case 'b': *tail++ = '\b'; break; - case 'f': *tail++ = '\f'; break; - case 'n': *tail++ = '\n'; break; - case 'r': *tail++ = '\r'; break; - case 't': *tail++ = '\t'; break; - case 'u': - { - auto from_hex = [](char c) - { - if (c >= 'a') - return c - 'a' + 10; - if (c >= 'A') - return c - 'A' + 10; - return c - '0'; - }; - unsigned int code = - (from_hex(head[1])<<12) + - (from_hex(head[2])<< 8) + - (from_hex(head[3])<< 4) + - from_hex(head[4]); - if (code >= 0x800) - { - *tail++ = 0xE0 | (code >> 12); - *tail++ = 0x80 | ((code >> 6) & 0x3F); - *tail++ = 0x80 | (code & 0x3F); - } - else if (code >= 0x80) - { - *tail++ = 0xC0 | (code >> 6); - *tail++ = 0x80 | (code & 0x3F); - } - else - { - *tail++ = code; - } - head += 4; - } - break; - } - } - else - *tail++ = *head; - head++; - } - end_ = tail; - *end_ = 0; - *(start_-1) = 0; - } - } - - detail::r_string s() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::String) - throw std::runtime_error("value is not string"); -#endif - unescape(); - return detail::r_string{start_, end_}; - } + template <> + struct single_tag_to_type<2> + { + using type = uint64_t; + }; - bool has(const char* str) const - { - return has(std::string(str)); - } + template <> + struct single_tag_to_type<3> + { + using type = double; + }; - bool has(const std::string& str) const - { - struct Pred - { - bool operator()(const rvalue& l, const rvalue& r) const - { - return l.key_ < r.key_; - }; - bool operator()(const rvalue& l, const std::string& r) const - { - return l.key_ < r; - }; - bool operator()(const std::string& l, const rvalue& r) const - { - return l < r.key_; - }; - }; - if (!is_cached()) - { - std::sort(begin(), end(), Pred()); - set_cached(); - } - auto it = lower_bound(begin(), end(), str, Pred()); - return it != end() && it->key_ == str; - } + template <> + struct single_tag_to_type<4> + { + using type = std::string; + }; - int count(const std::string& str) - { - return has(str) ? 1 : 0; - } + template <> + struct single_tag_to_type<5> + { + using type = std::string; + }; - rvalue* begin() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object && t() != type::List) - throw std::runtime_error("value is not a container"); -#endif - return l_.get(); - } - rvalue* end() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object && t() != type::List) - throw std::runtime_error("value is not a container"); -#endif - return l_.get()+lsize_; - } - const detail::r_string& key() const - { - return key_; - } + template + struct arguments + { + using subarguments = typename arguments::type; + using type = + typename subarguments::template push::type>; + }; - size_t size() const - { - if (t() == type::String) - return s().size(); -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object && t() != type::List) - throw std::runtime_error("value is not a container"); -#endif - return lsize_; - } + template <> + struct arguments<0> + { + using type = S<>; + }; - const rvalue& operator[](int index) const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::List) - throw std::runtime_error("value is not a list"); - if (index >= (int)lsize_ || index < 0) - throw std::runtime_error("list out of bound"); -#endif - return l_[index]; - } + template + struct last_element_type + { + using type = typename std::tuple_element>::type; + }; - const rvalue& operator[](size_t index) const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::List) - throw std::runtime_error("value is not a list"); - if (index >= lsize_) - throw std::runtime_error("list out of bound"); -#endif - return l_[index]; - } - const rvalue& operator[](const char* str) const - { - return this->operator[](std::string(str)); - } + template <> + struct last_element_type<> + { + }; - const rvalue& operator[](const std::string& str) const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object) - throw std::runtime_error("value is not an object"); -#endif - struct Pred - { - bool operator()(const rvalue& l, const rvalue& r) const - { - return l.key_ < r.key_; - }; - bool operator()(const rvalue& l, const std::string& r) const - { - return l.key_ < r; - }; - bool operator()(const std::string& l, const rvalue& r) const - { - return l < r.key_; - }; - }; - if (!is_cached()) - { - std::sort(begin(), end(), Pred()); - set_cached(); - } - auto it = lower_bound(begin(), end(), str, Pred()); - if (it != end() && it->key_ == str) - return *it; -#ifndef CROW_JSON_NO_ERROR_CHECK - throw std::runtime_error("cannot find key"); -#else - static rvalue nullValue; - return nullValue; -#endif - } - void set_error() - { - option_|=error_bit; - } + // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth + template using Invoke = typename T::type; - bool error() const - { - return (option_&error_bit)!=0; - } - private: - bool is_cached() const - { - return (option_&cached_bit)!=0; - } - void set_cached() const - { - option_ |= cached_bit; - } - void copy_l(const rvalue& r) - { - if (r.t() != type::Object && r.t() != type::List) - return; - lsize_ = r.lsize_; - lremain_ = 0; - l_.reset(new rvalue[lsize_]); - std::copy(r.begin(), r.end(), begin()); - } + template struct seq{ using type = seq; }; - void emplace_back(rvalue&& v) - { - if (!lremain_) - { - int new_size = lsize_ + lsize_; - if (new_size - lsize_ > 60000) - new_size = lsize_ + 60000; - if (new_size < 4) - new_size = 4; - rvalue* p = new rvalue[new_size]; - rvalue* p2 = p; - for(auto& x : *this) - *p2++ = std::move(x); - l_.reset(p); - lremain_ = new_size - lsize_; - } - l_[lsize_++] = std::move(v); - lremain_ --; - } + template struct concat; - mutable char* start_; - mutable char* end_; - detail::r_string key_; - std::unique_ptr l_; - uint32_t lsize_; - uint16_t lremain_; - type t_; - mutable uint8_t option_{0}; + template + struct concat, seq> + : seq{}; - friend rvalue load_nocopy_internal(char* data, size_t size); - friend rvalue load(const char* data, size_t size); - friend std::ostream& operator <<(std::ostream& os, const rvalue& r) - { - switch(r.t_) - { + template + using Concat = Invoke>; - case type::Null: os << "null"; break; - case type::False: os << "false"; break; - case type::True: os << "true"; break; - case type::Number: os << r.d(); break; - case type::String: os << '"' << r.s() << '"'; break; - case type::List: - { - os << '['; - bool first = true; - for(auto& x : r) - { - if (!first) - os << ','; - first = false; - os << x; - } - os << ']'; - } - break; - case type::Object: - { - os << '{'; - bool first = true; - for(auto& x : r) - { - if (!first) - os << ','; - os << '"' << escape(x.key_) << "\":"; - first = false; - os << x; - } - os << '}'; - } - break; - } - return os; - } + template struct gen_seq; + template using GenSeq = Invoke>; + + template + struct gen_seq : Concat, GenSeq>{}; + + template<> struct gen_seq<0> : seq<>{}; + template<> struct gen_seq<1> : seq<0>{}; + + template + struct pop_back_helper; + + template + struct pop_back_helper, Tuple> + { + template