aboutsummaryrefslogtreecommitdiffstats
path: root/json.h
diff options
context:
space:
mode:
authoripknHama <ipknhama@gmail.com>2014-04-17 22:32:21 +0900
committeripknHama <ipknhama@gmail.com>2014-04-17 22:32:50 +0900
commitd908a2657e67f436f8158436d69c496aab94bdaa (patch)
tree8459259b955fbda45c9f903c1fd98e7ea7b18809 /json.h
parentaf6bc11fb4360ca8a1f244283e51065ee38ffc80 (diff)
downloadcrow-d908a2657e67f436f8158436d69c496aab94bdaa.tar.gz
crow-d908a2657e67f436f8158436d69c496aab94bdaa.zip
preparing JSON library for flask++; complete writing feature
Diffstat (limited to 'json.h')
-rw-r--r--json.h474
1 files changed, 474 insertions, 0 deletions
diff --git a/json.h b/json.h
new file mode 100644
index 0000000..e060a42
--- /dev/null
+++ b/json.h
@@ -0,0 +1,474 @@
+#pragma once
+#include <iostream>
+
+#include <string>
+#include <unordered_map>
+
+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<const type*>(start_);
+ }
+ const void* data() const
+ {
+ return reinterpret_cast<const void*>(start_ + sizeof(intptr_t));
+ }
+
+ int i() const
+ {
+ if (t() != type::Number)
+ throw std::runtime_error("value is not number");
+ return static_cast<int>(*(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<const rvalue> 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<rvalue>
+ {
+ 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<rvalue>
+ {
+ // TODO
+ };
+ auto decode_number = [&]->boost::optional<rvalue>
+ {
+ // TODO
+ };
+ auto decode_value = [&]->boost::optional<rvalue>
+ {
+ 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<rvalue>
+ {
+ 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<std::vector<wvalue>> l;
+ std::unique_ptr<std::unordered_map<std::string, wvalue>> 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<std::vector<wvalue>>(new std::vector<wvalue>{}));
+ 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<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 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<std::string>(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<boost::asio::const_buffer> encode_ref(wvalue& v)
+ //{
+ //}
+ }
+}