#pragma once #include #include #include namespace flask { namespace json { enum class type : intptr_t { Null, False, True, Number, String, List, Object, }; const char* json_type_str = "\0\0\0\0\0\0\0\0" "\1\0\0\0\0\0\0\0" "\2\0\0\0\0\0\0\0" "\3\0\0\0\0\0\0\0" "\4\0\0\0\0\0\0\0" "\5\0\0\0\0\0\0\0" "\6\0\0\0\0\0\0\0"; struct r_string { operator std::string () { return std::string(s_, e_); } char* s_; char* e_; }; struct rvalue { rvalue() {} rvalue(type t) : start_{json_type_str + 8*(int)t}, end_{json_type_str+8*(int)t+8} {} ~rvalue() { deallocate(); } void deallocate() { if (mem_) { delete[] mem_; mem_ = nullptr; } } type t() const { return *reinterpret_cast(start_); } const void* data() const { return reinterpret_cast(start_ + sizeof(intptr_t)); } int i() const { if (t() != type::Number) throw std::runtime_error("value is not number"); return static_cast(*(double*)data()); } double d() const { if (t() != type::Number) throw std::runtime_error("value is not number"); return *(double*)data(); } r_string s() const { if (t() != type::Number) throw std::runtime_error("value is not number"); return {(char*)data(),(char*)data() + sizeof(char*)}; } const char* start_{}; const char* end_{}; char* mem_{}; }; //inline rvalue decode(const std::string& s) //{ //} /*inline boost::optional decode(const char* data, size_t size, bool partial = false) { static char* escaped = "\"\\\/\b\f\n\r\t" const char* e = data + size; auto ws_skip = [&] { while(data != e) { while(data != e && *data == ' ') ++data; while(data != e && *data == '\t') ++data; while(data != e && *data == '\r') ++data; while(data != e && *data == '\n') ++data; } }; auto decode_string = [&]->boost::optional { ws_skip(); if (data == e || *data != '"') return {}; while(data != e) { if (*data == '"') { } else if (*data == '\\') { // TODO //if (data+1 == e) //return {}; //data += 2; } else { data ++; } } }; auto decode_list = [&]->boost::optional { // TODO }; auto decode_number = [&]->boost::optional { // TODO }; auto decode_value = [&]->boost::optional { if (data == e) return {}; switch(*data) { case '"': emit_str_begin(); case '{': case 't': if (e-data >= 4 && data[1] == 'r' && data[2] == 'u' && data[3] == 'e') return rvalue(type::True); else return {}; case 'f': case 'n': } // TODO return {}; }; auto decode_object =[&]->boost::optional { ws_skip(); if (data == e || *data != '{') return {}; ws_skip(); if (data == e) return {}; if (*data == '}') return rvalue(type::Object); while(1) { auto t = decode_string(); ws_skip(); if (data == e) return {}; if (data != ':') return {}; auto v = decode_value(); ws_skip(); if (data == e) return {}; if (data == '}') break; if (data != ',') return {}; } // TODO build up object throw std::runtime_error("Not implemented"); return rvalue(type::Object); }; return decode_object(); } } } }*/ class wvalue { public: type t{type::Null}; private: double d; std::string s; std::unique_ptr> l; std::unique_ptr> o; public: wvalue() {} wvalue(wvalue&& r) : t(r.t), d(r.d), s{std::move(r.s)}, l{std::move(r.l)}, o{std::move(r.o)} { } 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; } wvalue& operator[](unsigned index) { if (t != type::List) reset(); t = type::List; if (!l) l = std::move(std::unique_ptr>(new std::vector{})); l->resize(index+1); return (*l)[index]; } 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 encode_internal(const wvalue& v, std::string& out); friend std::string encode(const wvalue& v); }; void encode_string(const std::string& str, std::string& out) { // TODO escaping out.push_back('"'); out += str; out.push_back('"'); } void encode_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: out += boost::lexical_cast(v.d); break; case type::String: encode_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; encode_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; encode_string(kv.first, out); out.push_back(':'); encode_internal(kv.second, out); } } out.push_back('}'); } break; } } std::string encode(const wvalue& v) { std::string ret; ret.reserve(v.estimate_length()); encode_internal(v, ret); return ret; } //std::vector encode_ref(wvalue& v) //{ //} } }