diff --git a/.gitattributes b/.gitattributes index 8781a7371f80b1..51f4625fb6d453 100644 --- a/.gitattributes +++ b/.gitattributes @@ -22,3 +22,4 @@ third_party/acados/*/t_renderer filter=lfs diff=lfs merge=lfs -text third_party/qt5/larch64/bin/lrelease filter=lfs diff=lfs merge=lfs -text third_party/qt5/larch64/bin/lupdate filter=lfs diff=lfs merge=lfs -text third_party/catch2/include/catch2/catch.hpp filter=lfs diff=lfs merge=lfs -text +third_party/nlohmann/json.hpp filter=lfs diff=lfs merge=lfs -text diff --git a/SConstruct b/SConstruct index 3faa978087fa84..5fa3c6f4fc144f 100644 --- a/SConstruct +++ b/SConstruct @@ -205,7 +205,7 @@ env = Environment( "#third_party/acados/include/hpipm/include", "#third_party/catch2/include", "#third_party/libyuv/include", - "#third_party/json11", + "#third_party/nlohmann", "#third_party/linux/include", "#third_party/snpe/include", "#third_party/mapbox-gl-native-qt/include", @@ -351,7 +351,7 @@ Export('env', 'qt_env', 'arch', 'real_arch') SConscript(['common/SConscript']) Import('_common', '_gpucommon') -common = [_common, 'json11'] +common = [_common] gpucommon = [_gpucommon] Export('common', 'gpucommon') diff --git a/common/SConscript b/common/SConscript index 829db6eeec0cc9..a8300a90e7d659 100644 --- a/common/SConscript +++ b/common/SConscript @@ -12,7 +12,7 @@ common_libs = [ if arch != "Darwin": common_libs.append('gpio.cc') -_common = env.Library('common', common_libs, LIBS="json11") +_common = env.Library('common', common_libs) files = [ 'clutil.cc', @@ -24,10 +24,10 @@ Export('_common', '_gpucommon') if GetOption('extras'): env.Program('tests/test_common', ['tests/test_runner.cc', 'tests/test_params.cc', 'tests/test_util.cc', 'tests/test_swaglog.cc'], - LIBS=[_common, 'json11', 'zmq', 'pthread']) + LIBS=[_common, 'zmq', 'pthread']) # Cython bindings -params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq', 'json11']) +params_python = envCython.Program('params_pyx.so', 'params_pyx.pyx', LIBS=envCython['LIBS'] + [_common, 'zmq']) SConscript([ 'transformations/SConscript', diff --git a/common/swaglog.cc b/common/swaglog.cc index 873836b725eb85..270e8665650928 100644 --- a/common/swaglog.cc +++ b/common/swaglog.cc @@ -11,7 +11,7 @@ #include #include -#include "third_party/json11/json11.hpp" +#include "nlohmann/json.hpp" #include "common/version.h" #include "system/hardware/hw.h" @@ -37,7 +37,7 @@ class SwaglogState { } } - ctx_j = json11::Json::object{}; + ctx_j = nlohmann::json(); if (char* dongle_id = getenv("DONGLE_ID")) { ctx_j["dongle_id"] = dongle_id; } @@ -66,17 +66,17 @@ class SwaglogState { void* zctx = nullptr; void* sock = nullptr; int print_level; - json11::Json::object ctx_j; + nlohmann::json ctx_j; }; bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS"); uint32_t NO_FRAME_ID = std::numeric_limits::max(); static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func, - char* msg_buf, const json11::Json::object &msg_j={}) { + char* msg_buf, const nlohmann::json &msg_j={}) { static SwaglogState s; - json11::Json::object log_j = json11::Json::object { + nlohmann::json log_j = nlohmann::json { {"ctx", s.ctx_j}, {"levelnum", levelnum}, {"filename", filename}, @@ -92,7 +92,7 @@ static void cloudlog_common(int levelnum, const char* filename, int lineno, cons std::string log_s; log_s += (char)levelnum; - ((json11::Json)log_j).dump(log_s); + log_s += log_j.dump(); s.log(levelnum, filename, lineno, func, msg_buf, log_s); free(msg_buf); @@ -115,14 +115,14 @@ void cloudlog_t_common(int levelnum, const char* filename, int lineno, const cha char* msg_buf = nullptr; int ret = vasprintf(&msg_buf, fmt, args); if (ret <= 0 || !msg_buf) return; - json11::Json::object tspt_j = json11::Json::object{ + nlohmann::json tspt_j = nlohmann::json{ {"event", msg_buf}, {"time", std::to_string(nanos_since_boot())} }; if (frame_id < NO_FRAME_ID) { tspt_j["frame_id"] = std::to_string(frame_id); } - tspt_j = json11::Json::object{{"timestamp", tspt_j}}; + tspt_j = nlohmann::json{{"timestamp", tspt_j}}; cloudlog_common(levelnum, filename, lineno, func, msg_buf, tspt_j); } diff --git a/common/tests/test_swaglog.cc b/common/tests/test_swaglog.cc index 09bc4c3795fd5e..be5ce51c2df206 100644 --- a/common/tests/test_swaglog.cc +++ b/common/tests/test_swaglog.cc @@ -7,7 +7,7 @@ #include "common/util.h" #include "common/version.h" #include "system/hardware/hw.h" -#include "third_party/json11/json11.hpp" +#include "nlohmann/json.hpp" std::string daemon_name = "testy"; std::string dongle_id = "test_dongle_id"; @@ -39,26 +39,25 @@ void recv_log(int thread_cnt, int thread_msg_cnt) { REQUIRE(buf[0] == CLOUDLOG_DEBUG); std::string err; - auto msg = json11::Json::parse(buf + 1, err); - REQUIRE(!msg.is_null()); + nlohmann::json msg = nlohmann::json::parse(buf + 1); - REQUIRE(msg["levelnum"].int_value() == CLOUDLOG_DEBUG); - REQUIRE_THAT(msg["filename"].string_value(), Catch::Contains("test_swaglog.cc")); - REQUIRE(msg["funcname"].string_value() == "log_thread"); - REQUIRE(msg["lineno"].int_value() == LINE_NO); + REQUIRE(msg["levelnum"].template get() == CLOUDLOG_DEBUG); + REQUIRE_THAT(msg["filename"].template get(), Catch::Contains("test_swaglog.cc")); + REQUIRE(msg["funcname"].template get() == "log_thread"); + REQUIRE(msg["lineno"].template get() == LINE_NO); auto ctx = msg["ctx"]; - REQUIRE(ctx["daemon"].string_value() == daemon_name); - REQUIRE(ctx["dongle_id"].string_value() == dongle_id); - REQUIRE(ctx["dirty"].bool_value() == true); + REQUIRE(ctx["daemon"].template get() == daemon_name); + REQUIRE(ctx["dongle_id"].template get() == dongle_id); + REQUIRE(ctx["dirty"].template get() == true); - REQUIRE(ctx["version"].string_value() == COMMA_VERSION); + REQUIRE(ctx["version"].template get() == COMMA_VERSION); std::string device = Hardware::get_name(); - REQUIRE(ctx["device"].string_value() == device); + REQUIRE(ctx["device"].template get() == device); - int thread_id = atoi(msg["msg"].string_value().c_str()); + int thread_id = atoi(msg["msg"].template get().c_str()); REQUIRE((thread_id >= 0 && thread_id < thread_cnt)); thread_msgs[thread_id]++; total_count++; diff --git a/release/files_common b/release/files_common index cf985f682daa25..342d5ff489c976 100644 --- a/release/files_common +++ b/release/files_common @@ -374,8 +374,7 @@ third_party/SConscript third_party/linux/** third_party/opencl/** -third_party/json11/json11.cpp -third_party/json11/json11.hpp +third_party/nlohmann/json.hpp third_party/qrcode/*.cc third_party/qrcode/*.hpp diff --git a/selfdrive/modeld/thneed/serialize.cc b/selfdrive/modeld/thneed/serialize.cc index 6ed5c08e811be3..56e0907eccfa2b 100644 --- a/selfdrive/modeld/thneed/serialize.cc +++ b/selfdrive/modeld/thneed/serialize.cc @@ -1,11 +1,11 @@ #include #include -#include "third_party/json11/json11.hpp" +#include "nlohmann/json.hpp" #include "common/util.h" #include "common/clutil.h" #include "selfdrive/modeld/thneed/thneed.h" -using namespace json11; +using namespace nlohmann; extern map g_program_source; @@ -14,25 +14,24 @@ void Thneed::load(const char *filename) { string buf = util::read_file(filename); int jsz = *(int *)buf.data(); - string jsonerr; string jj(buf.data() + sizeof(int), jsz); - Json jdat = Json::parse(jj, jsonerr); + json jdat = json::parse(jj); map real_mem; real_mem[NULL] = NULL; int ptr = sizeof(int)+jsz; - for (auto &obj : jdat["objects"].array_items()) { - auto mobj = obj.object_items(); - int sz = mobj["size"].int_value(); + for (auto &obj : jdat["objects"]) { + auto mobj = obj; + int sz = mobj["size"].template get(); cl_mem clbuf = NULL; - if (mobj["buffer_id"].string_value().size() > 0) { + if (mobj["buffer_id"].template get().size() > 0) { // image buffer must already be allocated - clbuf = real_mem[*(cl_mem*)(mobj["buffer_id"].string_value().data())]; - assert(mobj["needs_load"].bool_value() == false); + clbuf = real_mem[*(cl_mem*)(mobj["buffer_id"].template get().data())]; + assert(mobj["needs_load"].template get() == false); } else { - if (mobj["needs_load"].bool_value()) { + if (mobj["needs_load"].template get()) { clbuf = clCreateBuffer(context, CL_MEM_COPY_HOST_PTR | CL_MEM_READ_WRITE, sz, &buf[ptr], NULL); if (debug >= 1) printf("loading %p %d @ 0x%X\n", clbuf, sz, ptr); ptr += sz; @@ -48,9 +47,9 @@ void Thneed::load(const char *filename) { if (mobj["arg_type"] == "image2d_t" || mobj["arg_type"] == "image1d_t") { cl_image_desc desc = {0}; desc.image_type = (mobj["arg_type"] == "image2d_t") ? CL_MEM_OBJECT_IMAGE2D : CL_MEM_OBJECT_IMAGE1D_BUFFER; - desc.image_width = mobj["width"].int_value(); - desc.image_height = mobj["height"].int_value(); - desc.image_row_pitch = mobj["row_pitch"].int_value(); + desc.image_width = mobj["width"].template get(); + desc.image_height = mobj["height"].template get(); + desc.image_row_pitch = mobj["row_pitch"].template get(); assert(sz == desc.image_height*desc.image_row_pitch); #ifdef QCOM2 desc.buffer = clbuf; @@ -60,12 +59,12 @@ void Thneed::load(const char *filename) { #endif cl_image_format format = {0}; format.image_channel_order = CL_RGBA; - format.image_channel_data_type = mobj["float32"].bool_value() ? CL_FLOAT : CL_HALF_FLOAT; + format.image_channel_data_type = mobj["float32"].template get() ? CL_FLOAT : CL_HALF_FLOAT; cl_int errcode; #ifndef QCOM2 - if (mobj["needs_load"].bool_value()) { + if (mobj["needs_load"].template get()) { clbuf = clCreateImage(context, CL_MEM_COPY_HOST_PTR | CL_MEM_READ_WRITE, &format, &desc, &buf[ptr-sz], &errcode); } else { clbuf = clCreateImage(context, CL_MEM_READ_WRITE, &format, &desc, NULL, &errcode); @@ -80,22 +79,22 @@ void Thneed::load(const char *filename) { assert(clbuf != NULL); } - real_mem[*(cl_mem*)(mobj["id"].string_value().data())] = clbuf; + real_mem[*(cl_mem*)(mobj["id"].template get().data())] = clbuf; } map g_programs; - for (const auto &[name, source] : jdat["programs"].object_items()) { - if (debug >= 1) printf("building %s with size %zu\n", name.c_str(), source.string_value().size()); - g_programs[name] = cl_program_from_source(context, device_id, source.string_value()); + for (const auto &[name, source] : jdat["programs"].items()) { + if (debug >= 1) printf("building %s with size %zu\n", name.c_str(), source.template get().size()); + g_programs[name] = cl_program_from_source(context, device_id, source.template get()); } - for (auto &obj : jdat["inputs"].array_items()) { - auto mobj = obj.object_items(); - int sz = mobj["size"].int_value(); - cl_mem aa = real_mem[*(cl_mem*)(mobj["buffer_id"].string_value().data())]; + for (auto &obj : jdat["inputs"]) { + auto mobj = obj; + int sz = mobj["size"].template get(); + cl_mem aa = real_mem[*(cl_mem*)(mobj["buffer_id"].template get().data())]; input_clmem.push_back(aa); input_sizes.push_back(sz); - printf("Thneed::load: adding input %s with size %d\n", mobj["name"].string_value().data(), sz); + printf("Thneed::load: adding input %s with size %d\n", mobj["name"].template get().data(), sz); cl_int cl_err; void *ret = clEnqueueMapBuffer(command_queue, aa, CL_TRUE, CL_MAP_WRITE, 0, sz, 0, NULL, NULL, &cl_err); @@ -104,39 +103,39 @@ void Thneed::load(const char *filename) { inputs.push_back(ret); } - for (auto &obj : jdat["outputs"].array_items()) { - auto mobj = obj.object_items(); - int sz = mobj["size"].int_value(); + for (auto &obj : jdat["outputs"]) { + auto mobj = obj; + int sz = mobj["size"].template get(); printf("Thneed::save: adding output with size %d\n", sz); // TODO: support multiple outputs - output = real_mem[*(cl_mem*)(mobj["buffer_id"].string_value().data())]; + output = real_mem[*(cl_mem*)(mobj["buffer_id"].template get().data())]; assert(output != NULL); } - for (auto &obj : jdat["binaries"].array_items()) { - string name = obj["name"].string_value(); - size_t length = obj["length"].int_value(); + for (auto &obj : jdat["binaries"]) { + string name = obj["name"].template get(); + size_t length = obj["length"].template get(); if (debug >= 1) printf("binary %s with size %zu\n", name.c_str(), length); g_programs[name] = cl_program_from_binary(context, device_id, (const uint8_t*)&buf[ptr], length); ptr += length; } - for (auto &obj : jdat["kernels"].array_items()) { + for (auto &obj : jdat["kernels"]) { auto gws = obj["global_work_size"]; auto lws = obj["local_work_size"]; auto kk = shared_ptr(new CLQueuedKernel(this)); - kk->name = obj["name"].string_value(); + kk->name = obj["name"].template get(); kk->program = g_programs[kk->name]; - kk->work_dim = obj["work_dim"].int_value(); + kk->work_dim = obj["work_dim"].template get(); for (int i = 0; i < kk->work_dim; i++) { - kk->global_work_size[i] = gws[i].int_value(); - kk->local_work_size[i] = lws[i].int_value(); + kk->global_work_size[i] = gws[i].template get(); + kk->local_work_size[i] = lws[i].template get(); } - kk->num_args = obj["num_args"].int_value(); + kk->num_args = obj["num_args"].template get(); for (int i = 0; i < kk->num_args; i++) { - string arg = obj["args"].array_items()[i].string_value(); - int arg_size = obj["args_size"].array_items()[i].int_value(); + string arg = obj["args"][i].template get(); + int arg_size = obj["args_size"][i].template get(); kk->args_size.push_back(arg_size); if (arg_size == 8) { cl_mem val = *(cl_mem*)(arg.data()); diff --git a/selfdrive/modeld/thneed/thneed.h b/selfdrive/modeld/thneed/thneed.h index 47e18e0be3bb30..c5436a3847f857 100644 --- a/selfdrive/modeld/thneed/thneed.h +++ b/selfdrive/modeld/thneed/thneed.h @@ -18,9 +18,6 @@ using namespace std; cl_int thneed_clSetKernelArg(cl_kernel kernel, cl_uint arg_index, size_t arg_size, const void *arg_value); -namespace json11 { - class Json; -} class Thneed; class GPUMalloc { @@ -52,7 +49,6 @@ class CLQueuedKernel { vector args; vector args_size; cl_kernel kernel = NULL; - json11::Json to_json() const; cl_uint work_dim; size_t global_work_size[3] = {0}; diff --git a/selfdrive/navd/SConscript b/selfdrive/navd/SConscript index c116ef1535bd78..dfa6941c7f5baa 100644 --- a/selfdrive/navd/SConscript +++ b/selfdrive/navd/SConscript @@ -2,7 +2,7 @@ Import('qt_env', 'arch', 'common', 'messaging', 'visionipc', 'cereal', 'transfor map_env = qt_env.Clone() libs = ['qt_widgets', 'qt_util', 'qmapboxgl', common, messaging, cereal, visionipc, transformations, - 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread', 'json11'] + map_env["LIBS"] + 'zmq', 'capnp', 'kj', 'm', 'OpenCL', 'ssl', 'crypto', 'pthread'] + map_env["LIBS"] if arch == 'larch64': libs.append(':libEGL_mesa.so.0') diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index a3cba124fe79f0..53d9cdcc4263dd 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -91,7 +91,7 @@ if GetOption('extras') and arch != "Darwin": # setup and factory resetter qt_env.Program("qt/setup/reset", ["qt/setup/reset.cc"], LIBS=qt_libs) qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc", asset_obj], - LIBS=qt_libs + ['curl', 'common', 'json11']) + LIBS=qt_libs + ['curl', 'common']) # build updater UI qt_env.Program("qt/setup/updater", ["qt/setup/updater.cc", asset_obj], LIBS=qt_libs) @@ -126,4 +126,4 @@ if GetOption('extras') and arch != "Darwin": # build watch3 if arch in ['x86_64', 'aarch64', 'Darwin'] or GetOption('extras'): - qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'json11', 'zmq', 'visionipc', 'messaging']) + qt_env.Program("watch3", ["watch3.cc"], LIBS=qt_libs + ['common', 'zmq', 'visionipc', 'messaging']) diff --git a/system/logcatd/SConscript b/system/logcatd/SConscript index 6bd7c6ff3e8561..aaba60270add33 100644 --- a/system/logcatd/SConscript +++ b/system/logcatd/SConscript @@ -1,3 +1,3 @@ Import('env', 'cereal', 'messaging', 'common') -env.Program('logcatd', 'logcatd_systemd.cc', LIBS=[cereal, messaging, common, 'zmq', 'capnp', 'kj', 'systemd', 'json11']) +env.Program('logcatd', 'logcatd_systemd.cc', LIBS=[cereal, messaging, common, 'zmq', 'capnp', 'kj', 'systemd']) diff --git a/system/logcatd/logcatd_systemd.cc b/system/logcatd/logcatd_systemd.cc index 54b37821328203..4f98ac0d67ae9a 100644 --- a/system/logcatd/logcatd_systemd.cc +++ b/system/logcatd/logcatd_systemd.cc @@ -5,7 +5,7 @@ #include #include -#include "third_party/json11/json11.hpp" +#include "nlohmann/json.hpp" #include "cereal/messaging/messaging.h" #include "common/timing.h" @@ -62,7 +62,7 @@ int main(int argc, char *argv[]) { // Build message auto androidEntry = msg.initEvent().initAndroidLog(); androidEntry.setTs(timestamp); - androidEntry.setMessage(json11::Json(kv).dump()); + androidEntry.setMessage(nlohmann::json(kv).dump()); if (kv.count("_PID")) androidEntry.setPid(std::atoi(kv["_PID"].c_str())); if (kv.count("PRIORITY")) androidEntry.setPriority(std::atoi(kv["PRIORITY"].c_str())); if (kv.count("SYSLOG_IDENTIFIER")) androidEntry.setTag(kv["SYSLOG_IDENTIFIER"]); diff --git a/system/proclogd/SConscript b/system/proclogd/SConscript index 1f4b7670112260..e662991a48d9ab 100644 --- a/system/proclogd/SConscript +++ b/system/proclogd/SConscript @@ -1,5 +1,5 @@ Import('env', 'cereal', 'messaging', 'common') -libs = [cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj', 'common', 'zmq', 'json11'] +libs = [cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj', 'common', 'zmq'] env.Program('proclogd', ['main.cc', 'proclog.cc'], LIBS=libs) if GetOption('extras'): diff --git a/third_party/SConscript b/third_party/SConscript index e5bbfaa07a8d67..14def0611c77ad 100644 --- a/third_party/SConscript +++ b/third_party/SConscript @@ -1,6 +1,3 @@ Import('env') -env.Library('json11', ['json11/json11.cpp'], CCFLAGS=env['CCFLAGS'] + ['-Wno-unqualified-std-cast-call']) -env.Append(CPPPATH=[Dir('json11')]) - env.Library('kaitai', ['kaitai/kaitaistream.cpp'], CPPDEFINES=['KS_STR_ENCODING_NONE']) diff --git a/third_party/json11/json11.cpp b/third_party/json11/json11.cpp deleted file mode 100644 index bc4045f07d1954..00000000000000 --- a/third_party/json11/json11.cpp +++ /dev/null @@ -1,784 +0,0 @@ -/* Copyright (c) 2013 Dropbox, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "json11.hpp" -#include -#include -#include -#include -#include - -namespace json11 { - -static const int max_depth = 200; - -using std::string; -using std::vector; -using std::map; -using std::make_shared; -using std::initializer_list; -using std::move; - -/* Helper for representing null - just a do-nothing struct, plus comparison - * operators so the helpers in JsonValue work. We can't use nullptr_t because - * it may not be orderable. - */ -struct NullStruct { - bool operator==(NullStruct) const { return true; } - bool operator<(NullStruct) const { return false; } -}; - -/* * * * * * * * * * * * * * * * * * * * - * Serialization - */ - -static void dump(NullStruct, string &out) { - out += "null"; -} - -static void dump(double value, string &out) { - if (std::isfinite(value)) { - char buf[32]; - snprintf(buf, sizeof buf, "%.17g", value); - out += buf; - } else { - out += "null"; - } -} - -static void dump(int value, string &out) { - char buf[32]; - snprintf(buf, sizeof buf, "%d", value); - out += buf; -} - -static void dump(bool value, string &out) { - out += value ? "true" : "false"; -} - -static void dump(const string &value, string &out) { - out += '"'; - for (size_t i = 0; i < value.length(); i++) { - const char ch = value[i]; - if (ch == '\\') { - out += "\\\\"; - } else if (ch == '"') { - out += "\\\""; - } else if (ch == '\b') { - out += "\\b"; - } else if (ch == '\f') { - out += "\\f"; - } else if (ch == '\n') { - out += "\\n"; - } else if (ch == '\r') { - out += "\\r"; - } else if (ch == '\t') { - out += "\\t"; - } else if (static_cast(ch) <= 0x1f) { - char buf[8]; - snprintf(buf, sizeof buf, "\\u%04x", ch); - out += buf; - } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80 - && static_cast(value[i+2]) == 0xa8) { - out += "\\u2028"; - i += 2; - } else if (static_cast(ch) == 0xe2 && static_cast(value[i+1]) == 0x80 - && static_cast(value[i+2]) == 0xa9) { - out += "\\u2029"; - i += 2; - } else { - out += ch; - } - } - out += '"'; -} - -static void dump(const Json::array &values, string &out) { - bool first = true; - out += "["; - for (const auto &value : values) { - if (!first) - out += ", "; - value.dump(out); - first = false; - } - out += "]"; -} - -static void dump(const Json::object &values, string &out) { - bool first = true; - out += "{"; - for (const auto &kv : values) { - if (!first) - out += ", "; - dump(kv.first, out); - out += ": "; - kv.second.dump(out); - first = false; - } - out += "}"; -} - -void Json::dump(string &out) const { - m_ptr->dump(out); -} - -/* * * * * * * * * * * * * * * * * * * * - * Value wrappers - */ - -template -class Value : public JsonValue { -protected: - - // Constructors - explicit Value(const T &value) : m_value(value) {} - explicit Value(T &&value) : m_value(move(value)) {} - - // Get type tag - Json::Type type() const override { - return tag; - } - - // Comparisons - bool equals(const JsonValue * other) const override { - return m_value == static_cast *>(other)->m_value; - } - bool less(const JsonValue * other) const override { - return m_value < static_cast *>(other)->m_value; - } - - const T m_value; - void dump(string &out) const override { json11::dump(m_value, out); } -}; - -class JsonDouble final : public Value { - double number_value() const override { return m_value; } - int int_value() const override { return static_cast(m_value); } - bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } - bool less(const JsonValue * other) const override { return m_value < other->number_value(); } -public: - explicit JsonDouble(double value) : Value(value) {} -}; - -class JsonInt final : public Value { - double number_value() const override { return m_value; } - int int_value() const override { return m_value; } - bool equals(const JsonValue * other) const override { return m_value == other->number_value(); } - bool less(const JsonValue * other) const override { return m_value < other->number_value(); } -public: - explicit JsonInt(int value) : Value(value) {} -}; - -class JsonBoolean final : public Value { - bool bool_value() const override { return m_value; } -public: - explicit JsonBoolean(bool value) : Value(value) {} -}; - -class JsonString final : public Value { - const string &string_value() const override { return m_value; } -public: - explicit JsonString(const string &value) : Value(value) {} - explicit JsonString(string &&value) : Value(move(value)) {} -}; - -class JsonArray final : public Value { - const Json::array &array_items() const override { return m_value; } - const Json & operator[](size_t i) const override; -public: - explicit JsonArray(const Json::array &value) : Value(value) {} - explicit JsonArray(Json::array &&value) : Value(move(value)) {} -}; - -class JsonObject final : public Value { - const Json::object &object_items() const override { return m_value; } - const Json & operator[](const string &key) const override; -public: - explicit JsonObject(const Json::object &value) : Value(value) {} - explicit JsonObject(Json::object &&value) : Value(move(value)) {} -}; - -class JsonNull final : public Value { -public: - JsonNull() : Value({}) {} -}; - -/* * * * * * * * * * * * * * * * * * * * - * Static globals - static-init-safe - */ -struct Statics { - const std::shared_ptr null = make_shared(); - const std::shared_ptr t = make_shared(true); - const std::shared_ptr f = make_shared(false); - const string empty_string; - const vector empty_vector; - const map empty_map; - Statics() {} -}; - -static const Statics & statics() { - static const Statics s {}; - return s; -} - -static const Json & static_null() { - // This has to be separate, not in Statics, because Json() accesses statics().null. - static const Json json_null; - return json_null; -} - -/* * * * * * * * * * * * * * * * * * * * - * Constructors - */ - -Json::Json() noexcept : m_ptr(statics().null) {} -Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {} -Json::Json(double value) : m_ptr(make_shared(value)) {} -Json::Json(int value) : m_ptr(make_shared(value)) {} -Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {} -Json::Json(const string &value) : m_ptr(make_shared(value)) {} -Json::Json(string &&value) : m_ptr(make_shared(move(value))) {} -Json::Json(const char * value) : m_ptr(make_shared(value)) {} -Json::Json(const Json::array &values) : m_ptr(make_shared(values)) {} -Json::Json(Json::array &&values) : m_ptr(make_shared(move(values))) {} -Json::Json(const Json::object &values) : m_ptr(make_shared(values)) {} -Json::Json(Json::object &&values) : m_ptr(make_shared(move(values))) {} - -/* * * * * * * * * * * * * * * * * * * * - * Accessors - */ - -Json::Type Json::type() const { return m_ptr->type(); } -double Json::number_value() const { return m_ptr->number_value(); } -int Json::int_value() const { return m_ptr->int_value(); } -bool Json::bool_value() const { return m_ptr->bool_value(); } -const string & Json::string_value() const { return m_ptr->string_value(); } -const vector & Json::array_items() const { return m_ptr->array_items(); } -const map & Json::object_items() const { return m_ptr->object_items(); } -const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; } -const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; } - -double JsonValue::number_value() const { return 0; } -int JsonValue::int_value() const { return 0; } -bool JsonValue::bool_value() const { return false; } -const string & JsonValue::string_value() const { return statics().empty_string; } -const vector & JsonValue::array_items() const { return statics().empty_vector; } -const map & JsonValue::object_items() const { return statics().empty_map; } -const Json & JsonValue::operator[] (size_t) const { return static_null(); } -const Json & JsonValue::operator[] (const string &) const { return static_null(); } - -const Json & JsonObject::operator[] (const string &key) const { - auto iter = m_value.find(key); - return (iter == m_value.end()) ? static_null() : iter->second; -} -const Json & JsonArray::operator[] (size_t i) const { - if (i >= m_value.size()) return static_null(); - else return m_value[i]; -} - -/* * * * * * * * * * * * * * * * * * * * - * Comparison - */ - -bool Json::operator== (const Json &other) const { - if (m_ptr->type() != other.m_ptr->type()) - return false; - - return m_ptr->equals(other.m_ptr.get()); -} - -bool Json::operator< (const Json &other) const { - if (m_ptr->type() != other.m_ptr->type()) - return m_ptr->type() < other.m_ptr->type(); - - return m_ptr->less(other.m_ptr.get()); -} - -/* * * * * * * * * * * * * * * * * * * * - * Parsing - */ - -/* esc(c) - * - * Format char c suitable for printing in an error message. - */ -static inline string esc(char c) { - char buf[12]; - if (static_cast(c) >= 0x20 && static_cast(c) <= 0x7f) { - snprintf(buf, sizeof buf, "'%c' (%d)", c, c); - } else { - snprintf(buf, sizeof buf, "(%d)", c); - } - return string(buf); -} - -static inline bool in_range(long x, long lower, long upper) { - return (x >= lower && x <= upper); -} - -namespace { -/* JsonParser - * - * Object that tracks all state of an in-progress parse. - */ -struct JsonParser final { - - /* State - */ - const string &str; - size_t i; - string &err; - bool failed; - const JsonParse strategy; - - /* fail(msg, err_ret = Json()) - * - * Mark this parse as failed. - */ - Json fail(string &&msg) { - return fail(move(msg), Json()); - } - - template - T fail(string &&msg, const T err_ret) { - if (!failed) - err = std::move(msg); - failed = true; - return err_ret; - } - - /* consume_whitespace() - * - * Advance until the current character is non-whitespace. - */ - void consume_whitespace() { - while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') - i++; - } - - /* consume_comment() - * - * Advance comments (c-style inline and multiline). - */ - bool consume_comment() { - bool comment_found = false; - if (str[i] == '/') { - i++; - if (i == str.size()) - return fail("unexpected end of input after start of comment", false); - if (str[i] == '/') { // inline comment - i++; - // advance until next line, or end of input - while (i < str.size() && str[i] != '\n') { - i++; - } - comment_found = true; - } - else if (str[i] == '*') { // multiline comment - i++; - if (i > str.size()-2) - return fail("unexpected end of input inside multi-line comment", false); - // advance until closing tokens - while (!(str[i] == '*' && str[i+1] == '/')) { - i++; - if (i > str.size()-2) - return fail( - "unexpected end of input inside multi-line comment", false); - } - i += 2; - comment_found = true; - } - else - return fail("malformed comment", false); - } - return comment_found; - } - - /* consume_garbage() - * - * Advance until the current character is non-whitespace and non-comment. - */ - void consume_garbage() { - consume_whitespace(); - if(strategy == JsonParse::COMMENTS) { - bool comment_found = false; - do { - comment_found = consume_comment(); - if (failed) return; - consume_whitespace(); - } - while(comment_found); - } - } - - /* get_next_token() - * - * Return the next non-whitespace character. If the end of the input is reached, - * flag an error and return 0. - */ - char get_next_token() { - consume_garbage(); - if (failed) return (char)0; - if (i == str.size()) - return fail("unexpected end of input", (char)0); - - return str[i++]; - } - - /* encode_utf8(pt, out) - * - * Encode pt as UTF-8 and add it to out. - */ - void encode_utf8(long pt, string & out) { - if (pt < 0) - return; - - if (pt < 0x80) { - out += static_cast(pt); - } else if (pt < 0x800) { - out += static_cast((pt >> 6) | 0xC0); - out += static_cast((pt & 0x3F) | 0x80); - } else if (pt < 0x10000) { - out += static_cast((pt >> 12) | 0xE0); - out += static_cast(((pt >> 6) & 0x3F) | 0x80); - out += static_cast((pt & 0x3F) | 0x80); - } else { - out += static_cast((pt >> 18) | 0xF0); - out += static_cast(((pt >> 12) & 0x3F) | 0x80); - out += static_cast(((pt >> 6) & 0x3F) | 0x80); - out += static_cast((pt & 0x3F) | 0x80); - } - } - - /* parse_string() - * - * Parse a string, starting at the current position. - */ - string parse_string() { - string out; - long last_escaped_codepoint = -1; - while (true) { - if (i == str.size()) - return fail("unexpected end of input in string", ""); - - char ch = str[i++]; - - if (ch == '"') { - encode_utf8(last_escaped_codepoint, out); - return out; - } - - if (in_range(ch, 0, 0x1f)) - return fail("unescaped " + esc(ch) + " in string", ""); - - // The usual case: non-escaped characters - if (ch != '\\') { - encode_utf8(last_escaped_codepoint, out); - last_escaped_codepoint = -1; - out += ch; - continue; - } - - // Handle escapes - if (i == str.size()) - return fail("unexpected end of input in string", ""); - - ch = str[i++]; - - if (ch == 'u') { - // Extract 4-byte escape sequence - string esc = str.substr(i, 4); - // Explicitly check length of the substring. The following loop - // relies on std::string returning the terminating NUL when - // accessing str[length]. Checking here reduces brittleness. - if (esc.length() < 4) { - return fail("bad \\u escape: " + esc, ""); - } - for (size_t j = 0; j < 4; j++) { - if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F') - && !in_range(esc[j], '0', '9')) - return fail("bad \\u escape: " + esc, ""); - } - - long codepoint = strtol(esc.data(), nullptr, 16); - - // JSON specifies that characters outside the BMP shall be encoded as a pair - // of 4-hex-digit \u escapes encoding their surrogate pair components. Check - // whether we're in the middle of such a beast: the previous codepoint was an - // escaped lead (high) surrogate, and this is a trail (low) surrogate. - if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF) - && in_range(codepoint, 0xDC00, 0xDFFF)) { - // Reassemble the two surrogate pairs into one astral-plane character, per - // the UTF-16 algorithm. - encode_utf8((((last_escaped_codepoint - 0xD800) << 10) - | (codepoint - 0xDC00)) + 0x10000, out); - last_escaped_codepoint = -1; - } else { - encode_utf8(last_escaped_codepoint, out); - last_escaped_codepoint = codepoint; - } - - i += 4; - continue; - } - - encode_utf8(last_escaped_codepoint, out); - last_escaped_codepoint = -1; - - if (ch == 'b') { - out += '\b'; - } else if (ch == 'f') { - out += '\f'; - } else if (ch == 'n') { - out += '\n'; - } else if (ch == 'r') { - out += '\r'; - } else if (ch == 't') { - out += '\t'; - } else if (ch == '"' || ch == '\\' || ch == '/') { - out += ch; - } else { - return fail("invalid escape character " + esc(ch), ""); - } - } - } - - /* parse_number() - * - * Parse a double. - */ - Json parse_number() { - size_t start_pos = i; - - if (str[i] == '-') - i++; - - // Integer part - if (str[i] == '0') { - i++; - if (in_range(str[i], '0', '9')) - return fail("leading 0s not permitted in numbers"); - } else if (in_range(str[i], '1', '9')) { - i++; - while (in_range(str[i], '0', '9')) - i++; - } else { - return fail("invalid " + esc(str[i]) + " in number"); - } - - if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' - && (i - start_pos) <= static_cast(std::numeric_limits::digits10)) { - return std::atoi(str.c_str() + start_pos); - } - - // Decimal part - if (str[i] == '.') { - i++; - if (!in_range(str[i], '0', '9')) - return fail("at least one digit required in fractional part"); - - while (in_range(str[i], '0', '9')) - i++; - } - - // Exponent part - if (str[i] == 'e' || str[i] == 'E') { - i++; - - if (str[i] == '+' || str[i] == '-') - i++; - - if (!in_range(str[i], '0', '9')) - return fail("at least one digit required in exponent"); - - while (in_range(str[i], '0', '9')) - i++; - } - - return std::strtod(str.c_str() + start_pos, nullptr); - } - - /* expect(str, res) - * - * Expect that 'str' starts at the character that was just read. If it does, advance - * the input and return res. If not, flag an error. - */ - Json expect(const string &expected, Json res) { - assert(i != 0); - i--; - if (str.compare(i, expected.length(), expected) == 0) { - i += expected.length(); - return res; - } else { - return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length())); - } - } - - /* parse_json() - * - * Parse a JSON object. - */ - Json parse_json(int depth) { - if (depth > max_depth) { - return fail("exceeded maximum nesting depth"); - } - - char ch = get_next_token(); - if (failed) - return Json(); - - if (ch == '-' || (ch >= '0' && ch <= '9')) { - i--; - return parse_number(); - } - - if (ch == 't') - return expect("true", true); - - if (ch == 'f') - return expect("false", false); - - if (ch == 'n') - return expect("null", Json()); - - if (ch == '"') - return parse_string(); - - if (ch == '{') { - map data; - ch = get_next_token(); - if (ch == '}') - return data; - - while (1) { - if (ch != '"') - return fail("expected '\"' in object, got " + esc(ch)); - - string key = parse_string(); - if (failed) - return Json(); - - ch = get_next_token(); - if (ch != ':') - return fail("expected ':' in object, got " + esc(ch)); - - data[std::move(key)] = parse_json(depth + 1); - if (failed) - return Json(); - - ch = get_next_token(); - if (ch == '}') - break; - if (ch != ',') - return fail("expected ',' in object, got " + esc(ch)); - - ch = get_next_token(); - } - return data; - } - - if (ch == '[') { - vector data; - ch = get_next_token(); - if (ch == ']') - return data; - - while (1) { - i--; - data.push_back(parse_json(depth + 1)); - if (failed) - return Json(); - - ch = get_next_token(); - if (ch == ']') - break; - if (ch != ',') - return fail("expected ',' in list, got " + esc(ch)); - - ch = get_next_token(); - (void)ch; - } - return data; - } - - return fail("expected value, got " + esc(ch)); - } -}; -}//namespace { - -Json Json::parse(const string &in, string &err, JsonParse strategy) { - JsonParser parser { in, 0, err, false, strategy }; - Json result = parser.parse_json(0); - - // Check for any trailing garbage - parser.consume_garbage(); - if (parser.failed) - return Json(); - if (parser.i != in.size()) - return parser.fail("unexpected trailing " + esc(in[parser.i])); - - return result; -} - -// Documented in json11.hpp -vector Json::parse_multi(const string &in, - std::string::size_type &parser_stop_pos, - string &err, - JsonParse strategy) { - JsonParser parser { in, 0, err, false, strategy }; - parser_stop_pos = 0; - vector json_vec; - while (parser.i != in.size() && !parser.failed) { - json_vec.push_back(parser.parse_json(0)); - if (parser.failed) - break; - - // Check for another object - parser.consume_garbage(); - if (parser.failed) - break; - parser_stop_pos = parser.i; - } - return json_vec; -} - -/* * * * * * * * * * * * * * * * * * * * - * Shape-checking - */ - -bool Json::has_shape(const shape & types, string & err) const { - if (!is_object()) { - err = "expected JSON object, got " + dump(); - return false; - } - - for (auto & item : types) { - if ((*this)[item.first].type() != item.second) { - err = "bad type for " + item.first + " in " + dump(); - return false; - } - } - - return true; -} - -} // namespace json11 diff --git a/third_party/json11/json11.hpp b/third_party/json11/json11.hpp deleted file mode 100644 index 5202ef9323bb79..00000000000000 --- a/third_party/json11/json11.hpp +++ /dev/null @@ -1,232 +0,0 @@ -/* json11 - * - * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization. - * - * The core object provided by the library is json11::Json. A Json object represents any JSON - * value: null, bool, number (int or double), string (std::string), array (std::vector), or - * object (std::map). - * - * Json objects act like values: they can be assigned, copied, moved, compared for equality or - * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and - * Json::parse (static) to parse a std::string as a Json object. - * - * Internally, the various types of Json object are represented by the JsonValue class - * hierarchy. - * - * A note on numbers - JSON specifies the syntax of number formatting but not its semantics, - * so some JSON implementations distinguish between integers and floating-point numbers, while - * some don't. In json11, we choose the latter. Because some JSON implementations (namely - * Javascript itself) treat all numbers as the same type, distinguishing the two leads - * to JSON that will be *silently* changed by a round-trip through those implementations. - * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also - * provides integer helpers. - * - * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the - * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64 - * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch - * will be exact for +/- 275 years.) - */ - -/* Copyright (c) 2013 Dropbox, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#ifdef _MSC_VER - #if _MSC_VER <= 1800 // VS 2013 - #ifndef noexcept - #define noexcept throw() - #endif - - #ifndef snprintf - #define snprintf _snprintf_s - #endif - #endif -#endif - -namespace json11 { - -enum JsonParse { - STANDARD, COMMENTS -}; - -class JsonValue; - -class Json final { -public: - // Types - enum Type { - NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT - }; - - // Array and object typedefs - typedef std::vector array; - typedef std::map object; - - // Constructors for the various types of JSON value. - Json() noexcept; // NUL - Json(std::nullptr_t) noexcept; // NUL - Json(double value); // NUMBER - Json(int value); // NUMBER - Json(bool value); // BOOL - Json(const std::string &value); // STRING - Json(std::string &&value); // STRING - Json(const char * value); // STRING - Json(const array &values); // ARRAY - Json(array &&values); // ARRAY - Json(const object &values); // OBJECT - Json(object &&values); // OBJECT - - // Implicit constructor: anything with a to_json() function. - template - Json(const T & t) : Json(t.to_json()) {} - - // Implicit constructor: map-like objects (std::map, std::unordered_map, etc) - template ::value - && std::is_constructible::value, - int>::type = 0> - Json(const M & m) : Json(object(m.begin(), m.end())) {} - - // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc) - template ::value, - int>::type = 0> - Json(const V & v) : Json(array(v.begin(), v.end())) {} - - // This prevents Json(some_pointer) from accidentally producing a bool. Use - // Json(bool(some_pointer)) if that behavior is desired. - Json(void *) = delete; - - // Accessors - Type type() const; - - bool is_null() const { return type() == NUL; } - bool is_number() const { return type() == NUMBER; } - bool is_bool() const { return type() == BOOL; } - bool is_string() const { return type() == STRING; } - bool is_array() const { return type() == ARRAY; } - bool is_object() const { return type() == OBJECT; } - - // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not - // distinguish between integer and non-integer numbers - number_value() and int_value() - // can both be applied to a NUMBER-typed object. - double number_value() const; - int int_value() const; - - // Return the enclosed value if this is a boolean, false otherwise. - bool bool_value() const; - // Return the enclosed string if this is a string, "" otherwise. - const std::string &string_value() const; - // Return the enclosed std::vector if this is an array, or an empty vector otherwise. - const array &array_items() const; - // Return the enclosed std::map if this is an object, or an empty map otherwise. - const object &object_items() const; - - // Return a reference to arr[i] if this is an array, Json() otherwise. - const Json & operator[](size_t i) const; - // Return a reference to obj[key] if this is an object, Json() otherwise. - const Json & operator[](const std::string &key) const; - - // Serialize. - void dump(std::string &out) const; - std::string dump() const { - std::string out; - dump(out); - return out; - } - - // Parse. If parse fails, return Json() and assign an error message to err. - static Json parse(const std::string & in, - std::string & err, - JsonParse strategy = JsonParse::STANDARD); - static Json parse(const char * in, - std::string & err, - JsonParse strategy = JsonParse::STANDARD) { - if (in) { - return parse(std::string(in), err, strategy); - } else { - err = "null input"; - return nullptr; - } - } - // Parse multiple objects, concatenated or separated by whitespace - static std::vector parse_multi( - const std::string & in, - std::string::size_type & parser_stop_pos, - std::string & err, - JsonParse strategy = JsonParse::STANDARD); - - static inline std::vector parse_multi( - const std::string & in, - std::string & err, - JsonParse strategy = JsonParse::STANDARD) { - std::string::size_type parser_stop_pos; - return parse_multi(in, parser_stop_pos, err, strategy); - } - - bool operator== (const Json &rhs) const; - bool operator< (const Json &rhs) const; - bool operator!= (const Json &rhs) const { return !(*this == rhs); } - bool operator<= (const Json &rhs) const { return !(rhs < *this); } - bool operator> (const Json &rhs) const { return (rhs < *this); } - bool operator>= (const Json &rhs) const { return !(*this < rhs); } - - /* has_shape(types, err) - * - * Return true if this is a JSON object and, for each item in types, has a field of - * the given type. If not, return false and set err to a descriptive message. - */ - typedef std::initializer_list> shape; - bool has_shape(const shape & types, std::string & err) const; - -private: - std::shared_ptr m_ptr; -}; - -// Internal class hierarchy - JsonValue objects are not exposed to users of this API. -class JsonValue { -protected: - friend class Json; - friend class JsonInt; - friend class JsonDouble; - virtual Json::Type type() const = 0; - virtual bool equals(const JsonValue * other) const = 0; - virtual bool less(const JsonValue * other) const = 0; - virtual void dump(std::string &out) const = 0; - virtual double number_value() const; - virtual int int_value() const; - virtual bool bool_value() const; - virtual const std::string &string_value() const; - virtual const Json::array &array_items() const; - virtual const Json &operator[](size_t i) const; - virtual const Json::object &object_items() const; - virtual const Json &operator[](const std::string &key) const; - virtual ~JsonValue() {} -}; - -} // namespace json11 diff --git a/third_party/nlohmann/json.hpp b/third_party/nlohmann/json.hpp new file mode 100644 index 00000000000000..74986f9249ce91 --- /dev/null +++ b/third_party/nlohmann/json.hpp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9bea4c8066ef4a1c206b2be5a36302f8926f7fdc6087af5d20b417d0cf103ea6 +size 919975