Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarJson.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarJson.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/core/StarJson.cpp')
-rw-r--r--source/core/StarJson.cpp1015
1 files changed, 1015 insertions, 0 deletions
diff --git a/source/core/StarJson.cpp b/source/core/StarJson.cpp
new file mode 100644
index 0000000..7ef45ff
--- /dev/null
+++ b/source/core/StarJson.cpp
@@ -0,0 +1,1015 @@
+#include "StarJson.hpp"
+#include "StarJsonBuilder.hpp"
+#include "StarJsonPath.hpp"
+#include "StarFormat.hpp"
+#include "StarLexicalCast.hpp"
+#include "StarIterator.hpp"
+#include "StarFile.hpp"
+
+namespace Star {
+
+Json::Type Json::typeFromName(String const& t) {
+ if (t == "float")
+ return Type::Float;
+ else if (t == "bool")
+ return Type::Bool;
+ else if (t == "int")
+ return Type::Int;
+ else if (t == "string")
+ return Type::String;
+ else if (t == "array")
+ return Type::Array;
+ else if (t == "object")
+ return Type::Object;
+ else if (t == "null")
+ return Type::Null;
+ else
+ throw JsonException(strf("String '%s' is not a valid json type", t));
+}
+
+String Json::typeName(Type t) {
+ switch (t) {
+ case Type::Float:
+ return "float";
+ case Type::Bool:
+ return "bool";
+ case Type::Int:
+ return "int";
+ case Type::String:
+ return "string";
+ case Type::Array:
+ return "array";
+ case Type::Object:
+ return "object";
+ default:
+ return "null";
+ }
+}
+
+bool Json::operator==(const Json& v) const {
+ if (type() == Type::Null && v.type() == Type::Null) {
+ return true;
+ } else if (type() != v.type()) {
+ if ((type() == Type::Float || type() == Type::Int) && (v.type() == Type::Float || v.type() == Type::Int))
+ return toDouble() == v.toDouble() && toInt() == v.toInt();
+ return false;
+ } else {
+ if (type() == Type::Float)
+ return m_data.get<double>() == v.m_data.get<double>();
+ else if (type() == Type::Bool)
+ return m_data.get<bool>() == v.m_data.get<bool>();
+ else if (type() == Type::Int)
+ return m_data.get<int64_t>() == v.m_data.get<int64_t>();
+ else if (type() == Type::String)
+ return *m_data.get<StringConstPtr>() == *v.m_data.get<StringConstPtr>();
+ else if (type() == Type::Array)
+ return *m_data.get<JsonArrayConstPtr>() == *v.m_data.get<JsonArrayConstPtr>();
+ else if (type() == Type::Object)
+ return *m_data.get<JsonObjectConstPtr>() == *v.m_data.get<JsonObjectConstPtr>();
+ }
+ return false;
+}
+
+bool Json::operator!=(const Json& v) const {
+ return !(*this == v);
+}
+
+bool Json::unique() const {
+ if (m_data.is<StringConstPtr>())
+ return m_data.get<StringConstPtr>().unique();
+ else if (m_data.is<JsonArrayConstPtr>())
+ return m_data.get<JsonArrayConstPtr>().unique();
+ else if (m_data.is<JsonObjectConstPtr>())
+ return m_data.get<JsonObjectConstPtr>().unique();
+ else
+ return true;
+}
+
+Json Json::ofType(Type t) {
+ switch (t) {
+ case Type::Float:
+ return Json(0.0);
+ case Type::Bool:
+ return Json(false);
+ case Type::Int:
+ return Json(0);
+ case Type::String:
+ return Json("");
+ case Type::Array:
+ return Json(JsonArray());
+ case Type::Object:
+ return Json(JsonObject());
+ default:
+ return Json();
+ }
+}
+
+Json Json::parse(String const& string) {
+ return inputUtf32Json<String::const_iterator>(string.begin(), string.end(), true);
+}
+
+Json Json::parseJson(String const& json) {
+ return inputUtf32Json<String::const_iterator>(json.begin(), json.end(), false);
+}
+
+Json::Json() {}
+
+Json::Json(double d) {
+ m_data = d;
+}
+
+Json::Json(bool b) {
+ m_data = b;
+}
+
+Json::Json(int i) {
+ m_data = (int64_t)i;
+}
+
+Json::Json(long i) {
+ m_data = (int64_t)i;
+}
+
+Json::Json(long long i) {
+ m_data = (int64_t)i;
+}
+
+Json::Json(unsigned int i) {
+ m_data = (int64_t)i;
+}
+
+Json::Json(unsigned long i) {
+ m_data = (int64_t)i;
+}
+
+Json::Json(unsigned long long i) {
+ m_data = (int64_t)i;
+}
+
+Json::Json(char const* s) {
+ m_data = make_shared<String const>(s);
+}
+
+Json::Json(String::Char const* s) {
+ m_data = make_shared<String const>(s);
+}
+
+Json::Json(String::Char const* s, size_t len) {
+ m_data = make_shared<String const>(s, len);
+}
+
+Json::Json(String s) {
+ m_data = make_shared<String const>(std::move(s));
+}
+
+Json::Json(std::string s) {
+ m_data = make_shared<String const>((std::move(s)));
+}
+
+Json::Json(JsonArray l) {
+ m_data = make_shared<JsonArray const>(std::move(l));
+}
+
+Json::Json(JsonObject m) {
+ m_data = make_shared<JsonObject const>(std::move(m));
+}
+
+double Json::toDouble() const {
+ if (type() == Type::Float)
+ return m_data.get<double>();
+ if (type() == Type::Int)
+ return (double)m_data.get<int64_t>();
+
+ throw JsonException::format("Improper conversion to double from %s", typeName());
+}
+
+float Json::toFloat() const {
+ return (float)toDouble();
+}
+
+bool Json::toBool() const {
+ if (type() != Type::Bool)
+ throw JsonException::format("Improper conversion to bool from %s", typeName());
+ return m_data.get<bool>();
+}
+
+int64_t Json::toInt() const {
+ if (type() == Type::Float) {
+ return (int64_t)m_data.get<double>();
+ } else if (type() == Type::Int) {
+ return m_data.get<int64_t>();
+ } else {
+ throw JsonException::format("Improper conversion to int from %s", typeName());
+ }
+}
+
+uint64_t Json::toUInt() const {
+ if (type() == Type::Float) {
+ return (uint64_t)m_data.get<double>();
+ } else if (type() == Type::Int) {
+ return (uint64_t)m_data.get<int64_t>();
+ } else {
+ throw JsonException::format("Improper conversion to unsigned int from %s", typeName());
+ }
+}
+
+String Json::toString() const {
+ if (type() != Type::String)
+ throw JsonException(strf("Cannot convert from %s to string", typeName()));
+ return *m_data.get<StringConstPtr>();
+}
+
+JsonArray Json::toArray() const {
+ if (type() != Type::Array)
+ throw JsonException::format("Improper conversion to JsonArray from %s", typeName());
+ return *m_data.get<JsonArrayConstPtr>();
+}
+
+JsonObject Json::toObject() const {
+ if (type() != Type::Object)
+ throw JsonException::format("Improper conversion to JsonObject from %s", typeName());
+ return *m_data.get<JsonObjectConstPtr>();
+}
+
+StringConstPtr Json::stringPtr() const {
+ if (type() != Type::String)
+ throw JsonException(strf("Cannot convert from %s to string", typeName()));
+ return m_data.get<StringConstPtr>();
+}
+
+JsonArrayConstPtr Json::arrayPtr() const {
+ if (type() != Type::Array)
+ throw JsonException::format("Improper conversion to JsonArray from %s", typeName());
+ return m_data.get<JsonArrayConstPtr>();
+}
+
+JsonObjectConstPtr Json::objectPtr() const {
+ if (type() != Type::Object)
+ throw JsonException::format("Improper conversion to JsonObject from %s", typeName());
+ return m_data.get<JsonObjectConstPtr>();
+}
+
+Json::IteratorWrapper<JsonArray> Json::iterateArray() const {
+ return IteratorWrapper<JsonArray>{arrayPtr()};
+}
+
+Json::IteratorWrapper<JsonObject> Json::iterateObject() const {
+ return IteratorWrapper<JsonObject>{objectPtr()};
+}
+
+Maybe<Json> Json::opt() const {
+ if (isNull())
+ return {};
+ return *this;
+}
+
+Maybe<double> Json::optDouble() const {
+ if (isNull())
+ return {};
+ return toDouble();
+}
+
+Maybe<float> Json::optFloat() const {
+ if (isNull())
+ return {};
+ return toFloat();
+}
+
+Maybe<bool> Json::optBool() const {
+ if (isNull())
+ return {};
+ return toBool();
+}
+
+Maybe<int64_t> Json::optInt() const {
+ if (isNull())
+ return {};
+ return toInt();
+}
+
+Maybe<uint64_t> Json::optUInt() const {
+ if (isNull())
+ return {};
+ return toUInt();
+}
+
+Maybe<String> Json::optString() const {
+ if (isNull())
+ return {};
+ return toString();
+}
+
+Maybe<JsonArray> Json::optArray() const {
+ if (isNull())
+ return {};
+ return toArray();
+}
+
+Maybe<JsonObject> Json::optObject() const {
+ if (isNull())
+ return {};
+ return toObject();
+}
+
+size_t Json::size() const {
+ if (type() == Type::Array)
+ return m_data.get<JsonArrayConstPtr>()->size();
+ else if (type() == Type::Object)
+ return m_data.get<JsonObjectConstPtr>()->size();
+ else
+ throw JsonException("size() called on improper json type");
+}
+
+bool Json::contains(String const& key) const {
+ if (type() == Type::Object)
+ return m_data.get<JsonObjectConstPtr>()->contains(key);
+ else
+ throw JsonException("contains() called on improper json type");
+}
+
+Json Json::get(size_t index) const {
+ if (auto p = ptr(index))
+ return *p;
+ throw JsonException(strf("Json::get(%s) out of range", index));
+}
+
+double Json::getDouble(size_t index) const {
+ return get(index).toDouble();
+}
+
+float Json::getFloat(size_t index) const {
+ return get(index).toFloat();
+}
+
+bool Json::getBool(size_t index) const {
+ return get(index).toBool();
+}
+
+int64_t Json::getInt(size_t index) const {
+ return get(index).toInt();
+}
+
+uint64_t Json::getUInt(size_t index) const {
+ return get(index).toUInt();
+}
+
+String Json::getString(size_t index) const {
+ return get(index).toString();
+}
+
+JsonArray Json::getArray(size_t index) const {
+ return get(index).toArray();
+}
+
+JsonObject Json::getObject(size_t index) const {
+ return get(index).toObject();
+}
+
+Json Json::get(size_t index, Json def) const {
+ if (auto p = ptr(index))
+ return *p;
+ return def;
+}
+
+double Json::getDouble(size_t index, double def) const {
+ if (auto p = ptr(index))
+ return p->toDouble();
+ return def;
+}
+
+float Json::getFloat(size_t index, float def) const {
+ if (auto p = ptr(index))
+ return p->toFloat();
+ return def;
+}
+
+bool Json::getBool(size_t index, bool def) const {
+ if (auto p = ptr(index))
+ return p->toBool();
+ return def;
+}
+
+int64_t Json::getInt(size_t index, int64_t def) const {
+ if (auto p = ptr(index))
+ return p->toInt();
+ return def;
+}
+
+uint64_t Json::getUInt(size_t index, int64_t def) const {
+ if (auto p = ptr(index))
+ return p->toUInt();
+ return def;
+}
+
+String Json::getString(size_t index, String def) const {
+ if (auto p = ptr(index))
+ return p->toString();
+ return def;
+}
+
+JsonArray Json::getArray(size_t index, JsonArray def) const {
+ if (auto p = ptr(index))
+ return p->toArray();
+ return def;
+}
+
+JsonObject Json::getObject(size_t index, JsonObject def) const {
+ if (auto p = ptr(index))
+ return p->toObject();
+ return def;
+}
+
+Json Json::get(String const& key) const {
+ if (auto p = ptr(key))
+ return *p;
+ throw JsonException(strf("No such key in Json::get(\"%s\")", key));
+}
+
+double Json::getDouble(String const& key) const {
+ return get(key).toDouble();
+}
+
+float Json::getFloat(String const& key) const {
+ return get(key).toFloat();
+}
+
+bool Json::getBool(String const& key) const {
+ return get(key).toBool();
+}
+
+int64_t Json::getInt(String const& key) const {
+ return get(key).toInt();
+}
+
+uint64_t Json::getUInt(String const& key) const {
+ return get(key).toUInt();
+}
+
+String Json::getString(String const& key) const {
+ return get(key).toString();
+}
+
+JsonArray Json::getArray(String const& key) const {
+ return get(key).toArray();
+}
+
+JsonObject Json::getObject(String const& key) const {
+ return get(key).toObject();
+}
+
+Json Json::get(String const& key, Json def) const {
+ if (auto p = ptr(key))
+ return *p;
+ return def;
+}
+
+double Json::getDouble(String const& key, double def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toDouble();
+ return def;
+}
+
+float Json::getFloat(String const& key, float def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toFloat();
+ return def;
+}
+
+bool Json::getBool(String const& key, bool def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toBool();
+ return def;
+}
+
+int64_t Json::getInt(String const& key, int64_t def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toInt();
+ return def;
+}
+
+uint64_t Json::getUInt(String const& key, int64_t def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toUInt();
+ return def;
+}
+
+String Json::getString(String const& key, String def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toString();
+ return def;
+}
+
+JsonArray Json::getArray(String const& key, JsonArray def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toArray();
+ return def;
+}
+
+JsonObject Json::getObject(String const& key, JsonObject def) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toObject();
+ return def;
+}
+
+Maybe<Json> Json::opt(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return *p;
+ return {};
+}
+
+Maybe<double> Json::optDouble(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toDouble();
+ return {};
+}
+
+Maybe<float> Json::optFloat(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toFloat();
+ return {};
+}
+
+Maybe<bool> Json::optBool(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toBool();
+ return {};
+}
+
+Maybe<int64_t> Json::optInt(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toInt();
+ return {};
+}
+
+Maybe<uint64_t> Json::optUInt(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toUInt();
+ return {};
+}
+
+Maybe<String> Json::optString(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toString();
+ return {};
+}
+
+Maybe<JsonArray> Json::optArray(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toArray();
+ return {};
+}
+
+Maybe<JsonObject> Json::optObject(String const& key) const {
+ auto p = ptr(key);
+ if (p && *p)
+ return p->toObject();
+ return {};
+}
+
+Json Json::query(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q);
+}
+
+double Json::queryDouble(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toDouble();
+}
+
+float Json::queryFloat(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toFloat();
+}
+
+bool Json::queryBool(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toBool();
+}
+
+int64_t Json::queryInt(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toInt();
+}
+
+uint64_t Json::queryUInt(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toUInt();
+}
+
+String Json::queryString(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toString();
+}
+
+JsonArray Json::queryArray(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toArray();
+}
+
+JsonObject Json::queryObject(String const& q) const {
+ return JsonPath::pathGet(*this, JsonPath::parseQueryPath, q).toObject();
+}
+
+Json Json::query(String const& query, Json def) const {
+ if (auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query))
+ return *json;
+ return def;
+}
+
+double Json::queryDouble(String const& query, double def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toDouble();
+ return def;
+}
+
+float Json::queryFloat(String const& query, float def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toFloat();
+ return def;
+}
+
+bool Json::queryBool(String const& query, bool def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toBool();
+ return def;
+}
+
+int64_t Json::queryInt(String const& query, int64_t def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toInt();
+ return def;
+}
+
+uint64_t Json::queryUInt(String const& query, uint64_t def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toUInt();
+ return def;
+}
+
+String Json::queryString(String const& query, String def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toString();
+ return def;
+}
+
+JsonArray Json::queryArray(String const& query, JsonArray def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toArray();
+ return def;
+}
+
+JsonObject Json::queryObject(String const& query, JsonObject def) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, query);
+ if (json && *json)
+ return json->toObject();
+ return def;
+}
+
+Maybe<Json> Json::optQuery(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return *json;
+ return {};
+}
+
+Maybe<double> Json::optQueryDouble(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toDouble();
+ return {};
+}
+
+Maybe<float> Json::optQueryFloat(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toFloat();
+ return {};
+}
+
+Maybe<bool> Json::optQueryBool(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toBool();
+ return {};
+}
+
+Maybe<int64_t> Json::optQueryInt(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toInt();
+ return {};
+}
+
+Maybe<uint64_t> Json::optQueryUInt(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toUInt();
+ return {};
+}
+
+Maybe<String> Json::optQueryString(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toString();
+ return {};
+}
+
+Maybe<JsonArray> Json::optQueryArray(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toArray();
+ return {};
+}
+
+Maybe<JsonObject> Json::optQueryObject(String const& path) const {
+ auto json = JsonPath::pathFind(*this, JsonPath::parseQueryPath, path);
+ if (json && *json)
+ return json->toObject();
+ return {};
+}
+
+Json Json::set(String key, Json value) const {
+ auto map = toObject();
+ map[move(key)] = move(value);
+ return map;
+}
+
+Json Json::setPath(String path, Json value) const {
+ return JsonPath::pathSet(*this, JsonPath::parseQueryPath, path, value);
+}
+
+Json Json::erasePath(String path) const {
+ return JsonPath::pathRemove(*this, JsonPath::parseQueryPath, path);
+}
+
+Json Json::setAll(JsonObject values) const {
+ auto map = toObject();
+ for (auto& p : values)
+ map[move(p.first)] = move(p.second);
+ return map;
+}
+
+Json Json::eraseKey(String key) const {
+ auto map = toObject();
+ map.erase(move(key));
+ return map;
+}
+
+Json Json::set(size_t index, Json value) const {
+ auto array = toArray();
+ array[index] = move(value);
+ return array;
+}
+
+Json Json::insert(size_t index, Json value) const {
+ auto array = toArray();
+ array.insertAt(index, move(value));
+ return array;
+}
+
+Json Json::append(Json value) const {
+ auto array = toArray();
+ array.append(move(value));
+ return array;
+}
+
+Json Json::eraseIndex(size_t index) const {
+ auto array = toArray();
+ array.eraseAt(index);
+ return array;
+}
+
+Json::Type Json::type() const {
+ return (Type)m_data.typeIndex();
+}
+
+String Json::typeName() const {
+ return typeName(type());
+}
+
+Json Json::convert(Type u) const {
+ if (type() == u)
+ return *this;
+
+ switch (u) {
+ case Type::Null:
+ return Json();
+ case Type::Float:
+ return toDouble();
+ case Type::Bool:
+ return toBool();
+ case Type::Int:
+ return toInt();
+ case Type::String:
+ return toString();
+ case Type::Array:
+ return toArray();
+ case Type::Object:
+ return toObject();
+ default:
+ throw JsonException::format("Improper conversion to type %s", typeName(u));
+ }
+}
+
+bool Json::isType(Type t) const {
+ return type() == t;
+}
+
+bool Json::canConvert(Type t) const {
+ if (type() == t)
+ return true;
+
+ if (t == Type::Null)
+ return true;
+
+ if ((type() == Type::Float || type() == Type::Int) && (t == Type::Float || t == Type::Int))
+ return true;
+
+ return false;
+}
+
+bool Json::isNull() const {
+ return type() == Type::Null;
+}
+
+Json::operator bool() const {
+ return !isNull();
+}
+
+String Json::repr(int pretty, bool sort) const {
+ String result;
+ outputUtf32Json(*this, std::back_inserter(result), pretty, sort);
+ return result;
+}
+
+String Json::printJson(int pretty, bool sort) const {
+ if (type() != Type::Object && type() != Type::Array)
+ throw JsonException("printJson called on non-top-level JSON type");
+
+ return repr(pretty, sort);
+}
+
+std::ostream& operator<<(std::ostream& os, Json const& v) {
+ outputUtf8Json(v, std::ostream_iterator<char>(os), 0, false);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, JsonObject const& v) {
+ // Blargh copy
+ os << Json(v);
+ return os;
+}
+
+DataStream& operator<<(DataStream& os, const Json& v) {
+ // Compatibility with old serialization, 0 was INVALID but INVALID is no
+ // longer used.
+ os.write<uint8_t>((uint8_t)v.type() + 1);
+
+ if (v.type() == Json::Type::Float) {
+ os.write<double>(v.toDouble());
+ } else if (v.type() == Json::Type::Bool) {
+ os.write<bool>(v.toBool());
+ } else if (v.type() == Json::Type::Int) {
+ os.writeVlqI(v.toInt());
+ } else if (v.type() == Json::Type::String) {
+ os.write<String>(v.toString());
+ } else if (v.type() == Json::Type::Array) {
+ auto const& l = v.toArray();
+ os.writeVlqU(l.size());
+ for (auto const& v : l)
+ os.write<Json>(v);
+ } else if (v.type() == Json::Type::Object) {
+ auto const& m = v.toObject();
+ os.writeVlqU(m.size());
+ for (auto const& v : m) {
+ os.write<String>(v.first);
+ os.write<Json>(v.second);
+ }
+ }
+ return os;
+}
+
+DataStream& operator>>(DataStream& os, Json& v) {
+ // Compatibility with old serialization, 0 was INVALID but INVALID is no
+ // longer used.
+ uint8_t typeIndex = os.read<uint8_t>();
+ if (typeIndex > 0)
+ typeIndex -= 1;
+
+ Json::Type type = (Json::Type)typeIndex;
+
+ if (type == Json::Type::Float) {
+ v = Json(os.read<double>());
+ } else if (type == Json::Type::Bool) {
+ v = Json(os.read<bool>());
+ } else if (type == Json::Type::Int) {
+ v = Json(os.readVlqI());
+ } else if (type == Json::Type::String) {
+ v = Json(os.read<String>());
+ } else if (type == Json::Type::Array) {
+ JsonArray l;
+ size_t s = os.readVlqU();
+ for (size_t i = 0; i < s; ++i)
+ l.append(os.read<Json>());
+
+ v = move(l);
+ } else if (type == Json::Type::Object) {
+ JsonObject m;
+ size_t s = os.readVlqU();
+ for (size_t i = 0; i < s; ++i) {
+ String k = os.read<String>();
+ m[k] = os.read<Json>();
+ }
+
+ v = move(m);
+ }
+
+ return os;
+}
+
+DataStream& operator<<(DataStream& ds, JsonArray const& l) {
+ ds.writeContainer(l);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, JsonArray& l) {
+ ds.readContainer(l);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, JsonObject const& m) {
+ ds.writeMapContainer(m);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, JsonObject& m) {
+ ds.readMapContainer(m);
+ return ds;
+}
+
+size_t hash<Json>::operator()(Json const& v) const {
+ // This is probably a bit slow and weird, using the utf-8 output printer to
+ // produce a Json hash.
+
+ size_t h = 0;
+ auto collector = [&h](char c) { h = h * 101 + c; };
+ outputUtf8Json(v, makeFunctionOutputIterator(collector), 0, true);
+ return h;
+}
+
+Json const* Json::ptr(size_t index) const {
+ if (type() != Type::Array)
+ throw JsonException::format("Cannot call get with index on Json type %s, must be Array type", typeName());
+
+ auto const& list = *m_data.get<JsonArrayConstPtr>();
+ if (index >= list.size())
+ return nullptr;
+ return &list[index];
+}
+
+Json const* Json::ptr(String const& key) const {
+ if (type() != Type::Object)
+ throw JsonException::format("Cannot call get with key on Json type %s, must be Object type", typeName());
+ auto const& map = m_data.get<JsonObjectConstPtr>();
+
+ auto i = map->find(key);
+ if (i == map->end())
+ return nullptr;
+
+ return &i->second;
+}
+
+Json jsonMerge(Json const& base, Json const& merger) {
+ if (base.type() == Json::Type::Object && merger.type() == Json::Type::Object) {
+ JsonObject merged = base.toObject();
+ for (auto const& p : merger.toObject()) {
+ auto res = merged.insert(p);
+ if (!res.second)
+ res.first->second = jsonMerge(res.first->second, p.second);
+ }
+ return move(merged);
+
+ } else if (merger.type() == Json::Type::Null) {
+ return base;
+
+ } else {
+ return merger;
+ }
+}
+
+}