aboutsummaryrefslogtreecommitdiffstats
path: root/json.h
diff options
context:
space:
mode:
authoripknHama <ipknhama@gmail.com>2014-08-07 01:18:33 +0900
committeripknHama <ipknhama@gmail.com>2014-08-07 01:18:33 +0900
commit031615ac866cc3c8f1900dd4b4aae2106ad31230 (patch)
treeb8b7206ffbd2043368580ec269c97436929fe452 /json.h
parenta0c93f5b84cc11b30bc6320ac26127832ef8bf7a (diff)
downloadcrow-031615ac866cc3c8f1900dd4b4aae2106ad31230.tar.gz
crow-031615ac866cc3c8f1900dd4b4aae2106ad31230.zip
source resturcturing + CMake
Diffstat (limited to 'json.h')
-rw-r--r--json.h1346
1 files changed, 0 insertions, 1346 deletions
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 <string>
-#include <unordered_map>
-#include <iostream>
-#include <algorithm>
-#include <memory>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/operators.hpp>
-
-#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<r_string>,
- boost::less_than_comparable<r_string, std::string>,
- boost::equality_comparable<r_string>,
- boost::equality_comparable<r_string, std::string>
- {
- 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<int64_t>(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<double>(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<rvalue[]> 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<std::vector<wvalue>> l;
- std::unique_ptr<std::unordered_map<std::string, wvalue>> 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<std::vector<wvalue>>(new std::vector<wvalue>{}));
- 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<std::string, wvalue>
- >(
- new std::unordered_map<std::string, wvalue>{}));
- 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 <typename T>
- wvalue& operator[](const std::vector<T>& v)
- {
- if (t_ != type::List)
- reset();
- t_ = type::List;
- if (!l)
- l = std::move(std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{}));
- 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<std::vector<wvalue>>(new std::vector<wvalue>{}));
- 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<std::string, wvalue>
- >(
- new std::unordered_map<std::string, wvalue>{}));
- 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<boost::asio::const_buffer> dump_ref(wvalue& v)
- //{
- //}
- }
-}
-
-#undef crow_json_likely
-#undef crow_json_unlikely