From 031615ac866cc3c8f1900dd4b4aae2106ad31230 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Thu, 7 Aug 2014 01:18:33 +0900 Subject: source resturcturing + CMake --- json.h | 1346 ---------------------------------------------------------------- 1 file changed, 1346 deletions(-) delete mode 100644 json.h (limited to 'json.h') diff --git a/json.h b/json.h deleted file mode 100644 index 3d22b1e..0000000 --- a/json.h +++ /dev/null @@ -1,1346 +0,0 @@ -#pragma once - -//#define CROW_JSON_NO_ERROR_CHECK - -#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 - - -namespace crow -{ - namespace mustache - { - class template_t; - } - - namespace json - { - std::string escape(const std::string& str) - { - // TODO - return str; - } - - enum class type : char - { - Null, - False, - True, - Number, - String, - List, - Object, - }; - - class rvalue; - rvalue load(const char* data, size_t size); - - namespace detail - { - - 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; - } - - r_string& operator = (const r_string& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = 0; - return *this; - } - - operator std::string () const - { - return std::string(s_, e_); - } - - - const char* begin() const { return s_; } - const char* end() const { return e_; } - size_t size() const { return end() - begin(); } - - using iterator = const char*; - using const_iterator = const char*; - - 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); - }; - - bool operator < (const r_string& l, const r_string& r) - { - return boost::lexicographical_compare(l,r); - } - - bool operator < (const r_string& l, const std::string& r) - { - return boost::lexicographical_compare(l,r); - } - - bool operator > (const r_string& l, const std::string& r) - { - return boost::lexicographical_compare(r,l); - } - - bool operator == (const r_string& l, const r_string& r) - { - return boost::equals(l,r); - } - - bool operator == (const r_string& l, const std::string& r) - { - return boost::equals(l,r); - } - } - - class rvalue - { - 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} - {} - - rvalue(const rvalue& r) - : start_(r.start_), - end_(r.end_), - key_(r.key_), - t_(r.t_), - option_(r.option_) - { - copy_l(r); - } - - rvalue(rvalue&& r) noexcept - { - *this = std::move(r); - } - - 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; - } - - explicit operator bool() const noexcept - { - return (option_ & error_bit) == 0; - } - - explicit operator int64_t() const - { - return i(); - } - - explicit operator int() const - { - return i(); - } - - type t() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (option_ & error_bit) - { - throw std::runtime_error("invalid json object"); - } -#endif - return t_; - } - - 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_); - } - - 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++ = 0b11100000 | (code >> 12); - *tail++ = 0b10000000 | ((code >> 6) & 0b111111); - *tail++ = 0b10000000 | (code & 0b111111); - } - else if (code >= 0x80) - { - *tail++ = 0b11000000 | (code >> 6); - *tail++ = 0b10000000 | (code & 0b111111); - } - 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_}; - } - - bool has(const char* str) const - { - return has(std::string(str)); - } - - 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; - } - - int count(const std::string& str) - { - return has(str) ? 1 : 0; - } - - 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_; - } - - 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_; - } - - 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]; - } - - 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)); - } - - 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; - } - - 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()); - } - - 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_ --; - } - - 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}; - - 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_) - { - - 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; - } - }; - namespace detail { - } - - bool operator == (const rvalue& l, const std::string& r) - { - return l.s() == r; - } - - bool operator == (const std::string& l, const rvalue& r) - { - return l == r.s(); - } - - bool operator != (const rvalue& l, const std::string& r) - { - return l.s() != r; - } - - bool operator != (const std::string& l, const rvalue& r) - { - return l != r.s(); - } - - bool operator == (const rvalue& l, double r) - { - return l.d() == r; - } - - bool operator == (double l, const rvalue& r) - { - return l == r.d(); - } - - bool operator != (const rvalue& l, double r) - { - return l.d() != r; - } - - bool operator != (double l, const rvalue& r) - { - return l != r.d(); - } - - - //inline rvalue decode(const std::string& s) - //{ - //} - inline rvalue load_nocopy_internal(char* data, size_t size) - { - //static const char* escaped = "\"\\/\b\f\n\r\t"; - struct Parser - { - Parser(char* data, size_t size) - : data(data) - { - } - - bool consume(char c) - { - if (crow_json_unlikely(*data != c)) - return false; - data++; - return true; - } - - void ws_skip() - { - while(*data == ' ' || *data == '\t' || *data == '\r' || *data == '\n') ++data; - }; - - rvalue decode_string() - { - if (crow_json_unlikely(!consume('"'))) - return {}; - char* start = data; - uint8_t has_escaping = 0; - while(1) - { - if (crow_json_likely(*data != '"' && *data != '\\' && *data != '\0')) - { - data ++; - } - else if (*data == '"') - { - *data = 0; - *(start-1) = has_escaping; - data++; - return {type::String, start, data-1}; - } - else if (*data == '\\') - { - has_escaping = 1; - data++; - switch(*data) - { - case 'u': - { - auto check = [](char c) - { - return - ('0' <= c && c <= '9') || - ('a' <= c && c <= 'f') || - ('A' <= c && c <= 'F'); - }; - if (!(check(*(data+1)) && - check(*(data+2)) && - check(*(data+3)) && - check(*(data+4)))) - return {}; - } - data += 5; - break; - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - data ++; - break; - default: - return {}; - } - } - else - return {}; - } - return {}; - } - - rvalue decode_list() - { - rvalue ret(type::List); - if (crow_json_unlikely(!consume('['))) - { - ret.set_error(); - return ret; - } - ws_skip(); - if (crow_json_unlikely(*data == ']')) - { - data++; - return ret; - } - - while(1) - { - auto v = decode_value(); - if (crow_json_unlikely(!v)) - { - ret.set_error(); - break; - } - ws_skip(); - ret.emplace_back(std::move(v)); - if (*data == ']') - { - data++; - break; - } - if (crow_json_unlikely(!consume(','))) - { - ret.set_error(); - break; - } - ws_skip(); - } - return ret; - } - - rvalue decode_number() - { - char* start = data; - - enum NumberParsingState - { - Minus, - AfterMinus, - ZeroFirst, - Digits, - DigitsAfterPoints, - E, - DigitsAfterE, - Invalid, - } state{Minus}; - while(crow_json_likely(state != Invalid)) - { - switch(*data) - { - case '0': - state = (NumberParsingState)"\2\2\7\3\4\6\6"[state]; - /*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus) - { - state = NumberParsingState::ZeroFirst; - } - else if (state == NumberParsingState::Digits || - state == NumberParsingState::DigitsAfterE || - state == NumberParsingState::DigitsAfterPoints) - { - // ok; pass - } - else if (state == NumberParsingState::E) - { - state = NumberParsingState::DigitsAfterE; - } - else - return {};*/ - break; - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - state = (NumberParsingState)"\3\3\7\3\4\6\6"[state]; - while(*(data+1) >= '0' && *(data+1) <= '9') data++; - /*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus) - { - state = NumberParsingState::Digits; - } - else if (state == NumberParsingState::Digits || - state == NumberParsingState::DigitsAfterE || - state == NumberParsingState::DigitsAfterPoints) - { - // ok; pass - } - else if (state == NumberParsingState::E) - { - state = NumberParsingState::DigitsAfterE; - } - else - return {};*/ - break; - case '.': - state = (NumberParsingState)"\7\7\7\4\7\7\7"[state]; - /* - if (state == NumberParsingState::Digits) - { - state = NumberParsingState::DigitsAfterPoints; - } - else - return {}; - */ - break; - case '-': - state = (NumberParsingState)"\1\7\7\7\7\6\7"[state]; - /*if (state == NumberParsingState::Minus) - { - state = NumberParsingState::AfterMinus; - } - else if (state == NumberParsingState::E) - { - state = NumberParsingState::DigitsAfterE; - } - else - return {};*/ - break; - case '+': - state = (NumberParsingState)"\7\7\7\7\7\6\7"[state]; - /*if (state == NumberParsingState::E) - { - state = NumberParsingState::DigitsAfterE; - } - else - return {};*/ - break; - case 'e': case 'E': - state = (NumberParsingState)"\7\7\7\5\5\7\7"[state]; - /*if (state == NumberParsingState::Digits || - state == NumberParsingState::DigitsAfterPoints) - { - state = NumberParsingState::E; - } - else - return {};*/ - break; - default: - if (crow_json_likely(state == NumberParsingState::ZeroFirst || - state == NumberParsingState::Digits || - state == NumberParsingState::DigitsAfterPoints || - state == NumberParsingState::DigitsAfterE)) - return {type::Number, start, data}; - else - return {}; - } - data++; - } - - return {}; - } - - rvalue decode_value() - { - switch(*data) - { - case '[': - return decode_list(); - case '{': - return decode_object(); - case '"': - return decode_string(); - case 't': - if (//e-data >= 4 && - data[1] == 'r' && - data[2] == 'u' && - data[3] == 'e') - { - data += 4; - return {type::True}; - } - else - return {}; - case 'f': - if (//e-data >= 5 && - data[1] == 'a' && - data[2] == 'l' && - data[3] == 's' && - data[4] == 'e') - { - data += 5; - return {type::False}; - } - else - return {}; - case 'n': - if (//e-data >= 4 && - data[1] == 'u' && - data[2] == 'l' && - data[3] == 'l') - { - data += 4; - return {type::Null}; - } - else - return {}; - //case '1': case '2': case '3': - //case '4': case '5': case '6': - //case '7': case '8': case '9': - //case '0': case '-': - default: - return decode_number(); - } - return {}; - } - - rvalue decode_object() - { - rvalue ret(type::Object); - if (crow_json_unlikely(!consume('{'))) - { - ret.set_error(); - return ret; - } - - ws_skip(); - - if (crow_json_unlikely(*data == '}')) - { - data++; - return ret; - } - - while(1) - { - auto t = decode_string(); - if (crow_json_unlikely(!t)) - { - ret.set_error(); - break; - } - - ws_skip(); - if (crow_json_unlikely(!consume(':'))) - { - ret.set_error(); - break; - } - - // TODO caching key to speed up (flyweight?) - auto key = t.s(); - - ws_skip(); - auto v = decode_value(); - if (crow_json_unlikely(!v)) - { - ret.set_error(); - break; - } - ws_skip(); - - v.key_ = std::move(key); - ret.emplace_back(std::move(v)); - if (crow_json_unlikely(*data == '}')) - { - data++; - break; - } - if (crow_json_unlikely(!consume(','))) - { - ret.set_error(); - break; - } - ws_skip(); - } - return ret; - } - - rvalue parse() - { - ws_skip(); - auto ret = decode_value(); // or decode object? - ws_skip(); - if (ret && *data != '\0') - ret.set_error(); - return ret; - } - - char* data; - }; - return Parser(data, size).parse(); - } - inline rvalue load(const char* data, size_t size) - { - char* s = new char[size+1]; - memcpy(s, data, size); - s[size] = 0; - auto ret = load_nocopy_internal(s, size); - if (ret) - ret.key_.force(s, size); - else - delete[] s; - return ret; - } - - inline rvalue load(const char* data) - { - return load(data, strlen(data)); - } - - inline rvalue load(const std::string& str) - { - return load(str.data(), str.size()); - } - - class wvalue - { - friend class crow::mustache::template_t; - public: - type t() const { return t_; } - private: - type t_{type::Null}; - double d {}; - std::string s; - std::unique_ptr> l; - std::unique_ptr> o; - public: - - wvalue() {} - - wvalue(const rvalue& r) - { - t_ = r.t(); - switch(r.t()) - { - case type::Null: - case type::False: - case type::True: - return; - case type::Number: - d = r.d(); - return; - case type::String: - s = r.s(); - return; - case type::List: - l = std::move(std::unique_ptr>(new std::vector{})); - l->reserve(r.size()); - for(auto it = r.begin(); it != r.end(); ++it) - l->emplace_back(*it); - return; - case type::Object: - o = std::move( - std::unique_ptr< - std::unordered_map - >( - new std::unordered_map{})); - for(auto it = r.begin(); it != r.end(); ++it) - o->emplace(it->key(), *it); - return; - } - } - - wvalue(wvalue&& r) - { - *this = std::move(r); - } - - wvalue& operator = (wvalue&& r) - { - t_ = r.t_; - d = r.d; - s = std::move(r.s); - l = std::move(r.l); - o = std::move(r.o); - return *this; - } - - void clear() - { - t_ = type::Null; - l.reset(); - o.reset(); - } - - void reset() - { - t_ = type::Null; - l.reset(); - o.reset(); - } - - wvalue& operator = (std::nullptr_t) - { - reset(); - return *this; - } - wvalue& operator = (bool value) - { - reset(); - if (value) - t_ = type::True; - else - t_ = type::False; - return *this; - } - - wvalue& operator = (double value) - { - reset(); - t_ = type::Number; - d = value; - return *this; - } - - wvalue& operator = (uint16_t value) - { - reset(); - t_ = type::Number; - d = (double)value; - return *this; - } - - wvalue& operator = (int16_t value) - { - reset(); - t_ = type::Number; - d = (double)value; - return *this; - } - - wvalue& operator = (uint32_t value) - { - reset(); - t_ = type::Number; - d = (double)value; - return *this; - } - - wvalue& operator = (int32_t value) - { - reset(); - t_ = type::Number; - d = (double)value; - return *this; - } - - wvalue& operator = (uint64_t value) - { - reset(); - t_ = type::Number; - d = (double)value; - return *this; - } - - wvalue& operator = (int64_t value) - { - reset(); - t_ = type::Number; - d = (double)value; - return *this; - } - - wvalue& operator=(const char* str) - { - reset(); - t_ = type::String; - s = str; - return *this; - } - - wvalue& operator=(const std::string& str) - { - reset(); - t_ = type::String; - s = str; - return *this; - } - - template - wvalue& operator[](const std::vector& v) - { - if (t_ != type::List) - reset(); - t_ = type::List; - if (!l) - l = std::move(std::unique_ptr>(new std::vector{})); - l->clear(); - l->resize(v.size()); - size_t idx = 0; - for(auto& x:v) - { - (*l)[idx++] = x; - } - return *this; - } - - wvalue& operator[](unsigned index) - { - if (t_ != type::List) - reset(); - t_ = type::List; - if (!l) - l = std::move(std::unique_ptr>(new std::vector{})); - if (l->size() < index+1) - l->resize(index+1); - return (*l)[index]; - } - - int count(const std::string& str) - { - if (t_ != type::Object) - return 0; - if (!o) - return 0; - return o->count(str); - } - - wvalue& operator[](const std::string& str) - { - if (t_ != type::Object) - reset(); - t_ = type::Object; - if (!o) - o = std::move( - std::unique_ptr< - std::unordered_map - >( - new std::unordered_map{})); - return (*o)[str]; - } - - size_t estimate_length() const - { - switch(t_) - { - case type::Null: return 4; - case type::False: return 5; - case type::True: return 4; - case type::Number: return 30; - case type::String: return 2+s.size()+s.size()/2; - case type::List: - { - size_t sum{}; - if (l) - { - for(auto& x:*l) - { - sum += 1; - sum += x.estimate_length(); - } - } - return sum+2; - } - case type::Object: - { - size_t sum{}; - if (o) - { - for(auto& kv:*o) - { - sum += 2; - sum += 2+kv.first.size()+kv.first.size()/2; - sum += kv.second.estimate_length(); - } - } - return sum+2; - } - } - return 1; - } - - - friend void dump_internal(const wvalue& v, std::string& out); - friend std::string dump(const wvalue& v); - }; - - void dump_string(const std::string& str, std::string& out) - { - // TODO escaping - out.push_back('"'); - out += str; - out.push_back('"'); - } - void dump_internal(const wvalue& v, std::string& out) - { - switch(v.t_) - { - case type::Null: out += "null"; break; - case type::False: out += "false"; break; - case type::True: out += "true"; break; - case type::Number: - { - char outbuf[128]; - sprintf(outbuf, "%g", v.d); - out += outbuf; - } - break; - case type::String: dump_string(v.s, out); break; - case type::List: - { - out.push_back('['); - if (v.l) - { - bool first = true; - for(auto& x:*v.l) - { - if (!first) - { - out.push_back(','); - } - first = false; - dump_internal(x, out); - } - } - out.push_back(']'); - } - break; - case type::Object: - { - out.push_back('{'); - if (v.o) - { - bool first = true; - for(auto& kv:*v.o) - { - if (!first) - { - out.push_back(','); - } - first = false; - dump_string(kv.first, out); - out.push_back(':'); - dump_internal(kv.second, out); - } - } - out.push_back('}'); - } - break; - } - } - - std::string dump(const wvalue& v) - { - std::string ret; - ret.reserve(v.estimate_length()); - dump_internal(v, ret); - return ret; - } - - //std::vector dump_ref(wvalue& v) - //{ - //} - } -} - -#undef crow_json_likely -#undef crow_json_unlikely -- cgit v1.2.3-54-g00ecf