From e8bdf2cb5255965498e251530307f179d0b3bab8 Mon Sep 17 00:00:00 2001 From: Xuan Son Nguyen Date: Sat, 22 Aug 2026 01:37:12 +0200 Subject: [PATCH] various fixes --- common/json-schema-to-grammar.cpp | 4 -- common/json.cpp | 74 ++++++++++++++++++++----------- common/json.h | 9 +++- tools/cli/cli-context.cpp | 1 - tools/server/server-common.h | 1 - 5 files changed, 57 insertions(+), 32 deletions(-) diff --git a/common/json-schema-to-grammar.cpp b/common/json-schema-to-grammar.cpp index 2c873905d5..37c89e6b84 100644 --- a/common/json-schema-to-grammar.cpp +++ b/common/json-schema-to-grammar.cpp @@ -1,10 +1,6 @@ #include "json-schema-to-grammar.h" -// the grammar builder walks the schema with the library API -#include "json-shim.h" #include "common.h" -#include - #include #include #include diff --git a/common/json.cpp b/common/json.cpp index 40cff037c3..046294892f 100644 --- a/common/json.cpp +++ b/common/json.cpp @@ -18,6 +18,16 @@ using nlohmann::ordered_json; static_assert(sizeof(ordered_json) <= sizeof(common_json), "common_json storage is too small"); static_assert(alignof(ordered_json) <= alignof(common_json), "common_json alignment is too weak"); +// runs fn and gives every error of the backing library as a common_json_error +template +static decltype(auto) guard(F && fn) { + try { + return fn(); + } catch (const ordered_json::exception & e) { + throw common_json_error(e.what()); + } +} + static ordered_json & as_json(common_json * self) { return *reinterpret_cast(self); } @@ -42,7 +52,12 @@ static ordered_json to_json(const common_json_value & val) { case common_json_value::VAL_UINT: return val.val_uint; case common_json_value::VAL_DOUBLE: return val.val_double; case common_json_value::VAL_STRING: return val.val_string; - case common_json_value::VAL_JSON: return as_json(val.val_json.get()); + case common_json_value::VAL_JSON: + // one owner means no one else can see this tree, so it is safe to move it out + if (val.val_json.use_count() == 1) { + return std::move(as_json(val.val_json.get())); + } + return as_json(val.val_json.get()); } return nullptr; @@ -82,6 +97,9 @@ common_json_value::common_json_value(const char * val) { common_json_value::common_json_value(const common_json & val) : type(VAL_JSON), val_json(std::make_shared(val)) {} +common_json_value::common_json_value(common_json && val) : + type(VAL_JSON), val_json(std::make_shared(std::move(val))) {} + template common_json_value::common_json_value(const std::set & vals) : type(VAL_JSON) { common_json out = common_json::array(); @@ -259,15 +277,15 @@ bool common_json::operator!=(const common_json_value & val) const { return !(*this == val); } -common_json & common_json::at(const std::string & key) { return as_common(as_json(this).at(key)); } -const common_json & common_json::at(const std::string & key) const { return as_common(as_json(this).at(key)); } -common_json & common_json::at(size_t idx) { return as_common(as_json(this).at(idx)); } -const common_json & common_json::at(size_t idx) const { return as_common(as_json(this).at(idx)); } +common_json & common_json::at(const std::string & key) { return guard([&]() -> common_json & { return as_common(as_json(this).at(key)); }); } +const common_json & common_json::at(const std::string & key) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(key)); }); } +common_json & common_json::at(size_t idx) { return guard([&]() -> common_json & { return as_common(as_json(this).at(idx)); }); } +const common_json & common_json::at(size_t idx) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(idx)); }); } -common_json & common_json::operator[](const std::string & key) { return as_common(as_json(this)[key]); } -const common_json & common_json::operator[](const std::string & key) const { return as_common(as_json(this).at(key)); } -common_json & common_json::operator[](size_t idx) { return as_common(as_json(this)[idx]); } -const common_json & common_json::operator[](size_t idx) const { return as_common(as_json(this).at(idx)); } +common_json & common_json::operator[](const std::string & key) { return guard([&]() -> common_json & { return as_common(as_json(this)[key]); }); } +const common_json & common_json::operator[](const std::string & key) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(key)); }); } +common_json & common_json::operator[](size_t idx) { return guard([&]() -> common_json & { return as_common(as_json(this)[idx]); }); } +const common_json & common_json::operator[](size_t idx) const { return guard([&]() -> const common_json & { return as_common(as_json(this).at(idx)); }); } common_json & common_json::front() { return as_common(as_json(this).front()); } const common_json & common_json::front() const { return as_common(as_json(this).front()); } @@ -279,11 +297,11 @@ void common_json::clear() { } void common_json::erase(const std::string & key) { - as_json(this).erase(key); + guard([&] { as_json(this).erase(key); }); } void common_json::erase(size_t idx) { - as_json(this).erase(idx); + guard([&] { as_json(this).erase(idx); }); } void common_json::assign(const common_json_value & val) { @@ -291,17 +309,17 @@ void common_json::assign(const common_json_value & val) { } void common_json::set(const common_json_item & item) { - as_json(this)[item.key] = to_json(item.val); + guard([&] { as_json(this)[item.key] = to_json(item.val); }); } void common_json::push_back(const common_json_value & val) { - as_json(this).push_back(to_json(val)); + guard([&] { as_json(this).push_back(to_json(val)); }); } void common_json::push_back(std::initializer_list items) { common_json val(items); - as_json(this).push_back(as_json(&val)); + guard([&] { as_json(this).push_back(std::move(as_json(&val))); }); } size_t common_json::count(const std::string & key) const { @@ -309,13 +327,15 @@ size_t common_json::count(const std::string & key) const { } void common_json::insert(const common_json & vals) { - ordered_json & self = as_json(this); + guard([&] { + ordered_json & self = as_json(this); - self.insert(self.end(), as_json(&vals).begin(), as_json(&vals).end()); + self.insert(self.end(), as_json(&vals).begin(), as_json(&vals).end()); + }); } std::string common_json::dump(int indent) const { - return as_json(this).dump(indent); + return guard([&] { return as_json(this).dump(indent); }); } std::string common_json::dump_safe(int indent) const { @@ -324,15 +344,17 @@ std::string common_json::dump_safe(int indent) const { // an array is indexed directly, an object needs a walk from the start common_json & common_json::iterator::operator*() const { - if (as_json(node).is_object()) { - return as_common(std::next(as_json(node).begin(), idx).value()); - } + return guard([&]() -> common_json & { + if (as_json(node).is_object()) { + return as_common(std::next(as_json(node).begin(), idx).value()); + } - return as_common(as_json(node)[idx]); + return as_common(as_json(node)[idx]); + }); } std::string common_json::iterator::key() const { - return std::next(as_json(node).begin(), idx).key(); + return guard([&] { return std::next(as_json(node).begin(), idx).key(); }); } common_json::iterator common_json::begin() const { @@ -344,9 +366,11 @@ common_json::iterator common_json::end() const { } common_json::items_view::entry common_json::items_view::iterator::operator*() const { - auto it = std::next(as_json(node).begin(), idx); + return guard([&]() -> entry { + auto it = std::next(as_json(node).begin(), idx); - return { it.key(), as_common(it.value()) }; + return { it.key(), as_common(it.value()) }; + }); } common_json::items_view common_json::items() const { @@ -354,7 +378,7 @@ common_json::items_view common_json::items() const { } template T common_json::get() const { - return as_json(this).get(); + return guard([&] { return as_json(this).get(); }); } // the backing library cannot build a common_json, so this one is just a copy diff --git a/common/json.h b/common/json.h index 6f009b2a55..6f2d0841a1 100644 --- a/common/json.h +++ b/common/json.h @@ -4,6 +4,7 @@ // the underlay library is pimpl, it should never be exposed here // the backing value lives inside this object, so at() and the iterators give a real reference to it // note: object keys keep the order in which they are added +// note: every JSON error comes out as a common_json_error #include #include @@ -60,6 +61,7 @@ struct common_json_value { common_json_value(std::string_view val) : type(VAL_STRING), val_string(val) {} common_json_value(const char * val); common_json_value(const common_json & val); + common_json_value(common_json && val); // only for the types instantiated in json.cpp, the rest fails at link time template common_json_value(const std::vector & vals); // a set becomes an array, in the set's own order @@ -68,6 +70,8 @@ struct common_json_value { template common_json_value(const std::map & vals); // nested object, e.g. {"fn", {{"name", "x"}}} + // note: a nested pair {"a", "b"} becomes the object {"a": "b"}, not an array + // use common_json::array({"a", "b"}) to get an array common_json_value(std::initializer_list items); template ::value && !std::is_same::value, int>::type = 0> @@ -174,7 +178,7 @@ class common_json { bool operator==(const common_json_value & val) const; bool operator!=(const common_json_value & val) const; - // at() throws if the key is missing, operator[] adds a null value instead + // at() throws common_json_error if the key is missing, operator[] adds a null value instead common_json & at(const std::string & key); const common_json & at(const std::string & key) const; common_json & at(size_t idx); @@ -327,4 +331,7 @@ class common_json { alignas(8) unsigned char storage[32]; }; +// json.cpp defines this specialization, it must be declared before any use of it +template <> common_json common_json::get() const; + using common_json_entry = common_json::items_view::entry; diff --git a/tools/cli/cli-context.cpp b/tools/cli/cli-context.cpp index f6a9c74ac6..aa4eb76796 100644 --- a/tools/cli/cli-context.cpp +++ b/tools/cli/cli-context.cpp @@ -6,7 +6,6 @@ #include "log.h" #include "console.h" -#define JSON_ASSERT GGML_ASSERT #include "json.h" #include diff --git a/tools/server/server-common.h b/tools/server/server-common.h index 48dbdfcb63..6478d0218c 100644 --- a/tools/server/server-common.h +++ b/tools/server/server-common.h @@ -6,7 +6,6 @@ #include "chat.h" #include "mtmd.h" -#define JSON_ASSERT GGML_ASSERT #include "json.h" #include