From 4fbd8a615bae199cf282f6a51c351df6419e3f3c Mon Sep 17 00:00:00 2001 From: Xuan Son Nguyen Date: Sat, 22 Aug 2026 23:44:05 +0200 Subject: [PATCH] common: json.h: fix clang lto --- common/json.cpp | 48 ++++++++++++++++++++++-------------------------- common/json.h | 6 ++---- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/common/json.cpp b/common/json.cpp index 547542bb7d74..37713cef29e7 100644 --- a/common/json.cpp +++ b/common/json.cpp @@ -78,19 +78,21 @@ common_json_value::common_json_value(const common_json & val) : common_json_value::common_json_value(common_json && val) : type(VAL_JSON), val_json(std::make_shared(std::move(val))) {} +// the ctors and get() below are explicit specializations, giving strong symbols +// an explicit instantiation is a weak symbol, dropped by some LTO builds (clang-cl) template -common_json_value::common_json_value(const std::set & vals) : type(VAL_JSON) { +static std::shared_ptr set_json(const std::set & vals) { common_json out = common_json::array(); for (const auto & val : vals) { out.push_back(val); } - val_json = std::make_shared(std::move(out)); + return std::make_shared(std::move(out)); } // a set value is usable only for the types below -#define COMMON_JSON_SET(...) template common_json_value::common_json_value(const std::set<__VA_ARGS__> &); +#define COMMON_JSON_SET(...) template <> common_json_value::common_json_value(const std::set<__VA_ARGS__> & vals) : type(VAL_JSON), val_json(set_json(vals)) {} COMMON_JSON_SET(int) COMMON_JSON_SET(std::string) @@ -98,56 +100,45 @@ COMMON_JSON_SET(std::string) #undef COMMON_JSON_SET template -common_json_value::common_json_value(const std::map & vals) : type(VAL_JSON) { +static std::shared_ptr map_json(const T & vals) { common_json out = common_json::object(); for (const auto & val : vals) { out.set({ val.first, val.second }); } - val_json = std::make_shared(std::move(out)); + return std::make_shared(std::move(out)); } // a map value is usable only for the types below -#define COMMON_JSON_MAP(...) template common_json_value::common_json_value(const std::map &); +#define COMMON_JSON_MAP(...) template <> common_json_value::common_json_value(const std::map & vals) : type(VAL_JSON), val_json(map_json(vals)) {} COMMON_JSON_MAP(bool) COMMON_JSON_MAP(std::string) #undef COMMON_JSON_MAP -template -common_json_value::common_json_value(const std::unordered_map & vals) : type(VAL_JSON) { - common_json out = common_json::object(); - - for (const auto & val : vals) { - out.set({ val.first, val.second }); - } - - val_json = std::make_shared(std::move(out)); -} - // an unordered map value is usable only for the types below -#define COMMON_JSON_UMAP(...) template common_json_value::common_json_value(const std::unordered_map &); +#define COMMON_JSON_UMAP(...) template <> common_json_value::common_json_value(const std::unordered_map & vals) : type(VAL_JSON), val_json(map_json(vals)) {} COMMON_JSON_UMAP(size_t) #undef COMMON_JSON_UMAP template -common_json_value::common_json_value(const std::vector & vals) : type(VAL_JSON) { +static std::shared_ptr vec_json(const std::vector & vals) { common_json out = common_json::array(); for (const auto & val : vals) { out.push_back(val); } - val_json = std::make_shared(std::move(out)); + return std::make_shared(std::move(out)); } // a vector value is usable only for the types below // note: std::vector is not here, its proxy reference does not convert -#define COMMON_JSON_VEC(...) template common_json_value::common_json_value(const std::vector<__VA_ARGS__> &); +#define COMMON_JSON_VEC(...) template <> common_json_value::common_json_value(const std::vector<__VA_ARGS__> & vals) : type(VAL_JSON), val_json(vec_json(vals)) {} COMMON_JSON_VEC(int) COMMON_JSON_VEC(unsigned char) @@ -404,10 +395,6 @@ common_json::items_view common_json::items() const { return items_view(const_cast(this), size()); } -template T common_json::get() const { - return guard([&] { return as_json(this).get(); }); -} - // the backing library cannot build a common_json, so this one is just a copy template <> common_json common_json::get() const { return *this; @@ -415,7 +402,7 @@ template <> common_json common_json::get() const { // get() is usable only for the types below -#define COMMON_JSON_GET(...) template __VA_ARGS__ common_json::get<__VA_ARGS__>() const; +#define COMMON_JSON_GET(...) template <> __VA_ARGS__ common_json::get<__VA_ARGS__>() const { return guard([&] { return as_json(this).get<__VA_ARGS__>(); }); } COMMON_JSON_GET(bool) COMMON_JSON_GET(int) @@ -435,3 +422,12 @@ COMMON_JSON_GET(std::vector) COMMON_JSON_GET(std::unordered_map) #undef COMMON_JSON_GET + +// must stay below the get specialization +common_json::operator std::string() const { + return get(); +} + +std::string common_json::value(const std::string & key, const char * def) const { + return contains(key) ? at(key).get() : std::string(def); +} diff --git a/common/json.h b/common/json.h index 9e20a2adb2f0..f3ad4edee8b0 100644 --- a/common/json.h +++ b/common/json.h @@ -221,16 +221,14 @@ class common_json { // implicit get() for plain values, so they can be assigned to their C++ type directly // note: kept to this short list on purpose, a wider one makes j["key"] ambiguous // note: a numeric one would make "str = json;" ambiguous, a number converts to char too - operator std::string() const { return get(); } + operator std::string() const; template T value(const std::string & key, T def) const { return contains(key) ? at(key).get() : def; } - std::string value(const std::string & key, const char * def) const { - return contains(key) ? at(key).get() : std::string(def); - } + std::string value(const std::string & key, const char * def) const; // a JSON default needs no get(), it is already the right type common_json value(const std::string & key, const common_json & def) const {