From 07a8fe6a235a91e9ad9bd69fae25a3ed07162ac0 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Fri, 10 Jan 2025 18:17:00 -0500 Subject: [PATCH 1/5] Drop pre-C++11 alternatives (#1593) * Assume C++11 We already assume C++11 elsewhere, so all pre-11 `#ifdef` branches are dead code at this point. Fixes issue #1591 because we can just use `std::isfinite` etc. assume C++11 in json_reader.cpp as well apply clang-format * valueToString: simplify lookup of special float name --- AUTHORS | 2 +- src/lib_json/json_reader.cpp | 11 ----- src/lib_json/json_writer.cpp | 79 ++++-------------------------------- 3 files changed, 9 insertions(+), 83 deletions(-) diff --git a/AUTHORS b/AUTHORS index e1fa0fc3a..7a3def276 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,7 +16,7 @@ Baruch Siach Ben Boeckel Benjamin Knecht Bernd Kuhls -Billy Donahue +Billy Donahue Braden McDorman Brandon Myers Brendan Drew diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index 10c97aecb..5b6299906 100644 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -23,13 +23,6 @@ #include #include -#if __cplusplus >= 201103L - -#if !defined(sscanf) -#define sscanf std::sscanf -#endif - -#endif //__cplusplus #if defined(_MSC_VER) #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) @@ -53,11 +46,7 @@ static size_t const stackLimit_g = namespace Json { -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) using CharReaderPtr = std::unique_ptr; -#else -using CharReaderPtr = std::auto_ptr; -#endif // Implementation of class Features // //////////////////////////////// diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index ee45c43ba..ac14eb11f 100644 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,67 +19,6 @@ #include #include -#if __cplusplus >= 201103L -#include -#include - -#if !defined(isnan) -#define isnan std::isnan -#endif - -#if !defined(isfinite) -#define isfinite std::isfinite -#endif - -#else -#include -#include - -#if defined(_MSC_VER) -#if !defined(isnan) -#include -#define isnan _isnan -#endif - -#if !defined(isfinite) -#include -#define isfinite _finite -#endif - -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - -#endif //_MSC_VER - -#if defined(__sun) && defined(__SVR4) // Solaris -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#endif - -#if defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) \ - ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) -#endif -#endif -#endif - -#if !defined(isnan) -// IEEE standard states that NaN values will not compare to themselves -#define isnan(x) ((x) != (x)) -#endif - -#if !defined(__APPLE__) -#if !defined(isfinite) -#define isfinite finite -#endif -#endif -#endif - #if defined(_MSC_VER) // Disable warning about strdup being deprecated. #pragma warning(disable : 4996) @@ -85,11 +26,7 @@ namespace Json { -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) using StreamWriterPtr = std::unique_ptr; -#else -using StreamWriterPtr = std::auto_ptr; -#endif String valueToString(LargestInt value) { UIntToStringBuffer buffer; @@ -129,12 +66,12 @@ String valueToString(double value, bool useSpecialFloats, // Print into the buffer. We need not request the alternative representation // that always has a decimal point because JSON doesn't distinguish the // concepts of reals and integers. - if (!isfinite(value)) { - static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, - {"null", "-1e+9999", "1e+9999"}}; - return reps[useSpecialFloats ? 0 : 1][isnan(value) ? 0 - : (value < 0) ? 1 - : 2]; + if (!std::isfinite(value)) { + if (std::isnan(value)) + return useSpecialFloats ? "NaN" : "null"; + if (value < 0) + return useSpecialFloats ? "-Infinity" : "-1e+9999"; + return useSpecialFloats ? "Infinity" : "1e+9999"; } String buffer(size_t(36), '\0'); From 60ccc1f5deb671e95d2a6cc761f6d03f3c8ade07 Mon Sep 17 00:00:00 2001 From: evalon32 <34560232+evalon32@users.noreply.github.com> Date: Fri, 10 Jan 2025 18:25:25 -0500 Subject: [PATCH 2/5] feat: support std::string_view in Value API (#1584) This adds direct support for `std::string_view` when available (C++17 and above). The current API can be used with `std::string_view` via the low-level two-pointer methods, but is not ergonomic. E.g., compare: ``` Json::Value node; std::string foo, bar, baz; std::string_view foo_sv, bar_sv, baz_sv; // Efficient & readable: node[foo][bar][baz]; // Less efficient, less readable: node[std::string(foo_sv)][std::string(bar_sv)][std::string(baz_sv)]; // Efficient, but a lot less readable: *node.demand(foo_sv.data(), foo_sv.data() + foo_sv.size()) ->demand(bar_sv.data(), bar_sv.data() + bar_sv.size()) ->demand(baz_sv.data(), baz_sv.data() + baz_sv.size()) // After this change, efficient & readable: node[foo_sv][bar_sv][baz_sv]; ``` * The constructor can take a `std::string_view` parameter. The existing overloads taking `const std::string&` and `const char*` are still necessary to support assignment from those types. * `operator[]`, `get()`, `isMember()` and `removeMember()` take a `std::string_view` parameter. This supersedes the overloads taking `const std::string&` and `const char*`. The overloads taking a pair of pointers (begin, end) are preserved for source compatibility. * `getString()` has an overload with a `std::string_view` output parameter. The one with a pair of pointers is preserved for source compatibility. Signed-off-by: Lev Kandel Co-authored-by: Jordan Bayles --- include/json/value.h | 61 +++++++++++++++++++++++++++---- src/lib_json/json_value.cpp | 71 +++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 7 deletions(-) diff --git a/include/json/value.h b/include/json/value.h index 073ed30d9..307493298 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -39,6 +39,10 @@ #endif #endif +#if __cplusplus >= 201703L +#define JSONCPP_HAS_STRING_VIEW 1 +#endif + #include #include #include @@ -46,6 +50,10 @@ #include #include +#ifdef JSONCPP_HAS_STRING_VIEW +#include +#endif + // Disable warning C4251: : needs to have dll-interface to // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) @@ -342,6 +350,9 @@ class JSON_API Value { */ Value(const StaticString& value); Value(const String& value); +#ifdef JSONCPP_HAS_STRING_VIEW + Value(std::string_view value); +#endif Value(bool value); Value(std::nullptr_t ptr) = delete; Value(const Value& other); @@ -384,6 +395,12 @@ class JSON_API Value { * \return false if !string. (Seg-fault if str or end are NULL.) */ bool getString(char const** begin, char const** end) const; +#ifdef JSONCPP_HAS_STRING_VIEW + /** Get string_view of string-value. + * \return false if !string. (Seg-fault if str is NULL.) + */ + bool getString(std::string_view* str) const; +#endif Int asInt() const; UInt asUInt() const; #if defined(JSON_HAS_INT64) @@ -470,6 +487,15 @@ class JSON_API Value { bool insert(ArrayIndex index, const Value& newValue); bool insert(ArrayIndex index, Value&& newValue); +#ifdef JSONCPP_HAS_STRING_VIEW + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](std::string_view key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](std::string_view key) const; +#else /// Access an object value by name, create a null member if it does not exist. /// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// Exceeding that will cause an exception. @@ -484,6 +510,7 @@ class JSON_API Value { /// that name. /// \param key may contain embedded nulls. const Value& operator[](const String& key) const; +#endif /** \brief Access an object value by name, create a null member if it does not * exist. * @@ -497,18 +524,24 @@ class JSON_API Value { * \endcode */ Value& operator[](const StaticString& key); +#ifdef JSONCPP_HAS_STRING_VIEW /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy - Value get(const char* key, const Value& defaultValue) const; + Value get(std::string_view key, const Value& defaultValue) const; +#else /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy - /// \note key may contain embedded nulls. - Value get(const char* begin, const char* end, - const Value& defaultValue) const; + Value get(const char* key, const Value& defaultValue) const; /// Return the member named key if it exist, defaultValue otherwise. /// \note deep copy /// \param key may contain embedded nulls. Value get(const String& key, const Value& defaultValue) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, + const Value& defaultValue) const; /// Most general and efficient version of isMember()const, get()const, /// and operator[]const /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 @@ -525,20 +558,28 @@ class JSON_API Value { /// Do nothing if it did not exist. /// \pre type() is objectValue or nullValue /// \post type() is unchanged +#if JSONCPP_HAS_STRING_VIEW + void removeMember(std::string_view key); +#else void removeMember(const char* key); /// Same as removeMember(const char*) /// \param key may contain embedded nulls. void removeMember(const String& key); - /// Same as removeMember(const char* begin, const char* end, Value* removed), - /// but 'key' is null-terminated. - bool removeMember(const char* key, Value* removed); +#endif /** \brief Remove the named map member. * * Update 'removed' iff removed. * \param key may contain embedded nulls. * \return true iff removed (no exceptions) */ +#if JSONCPP_HAS_STRING_VIEW + bool removeMember(std::string_view key, Value* removed); +#else bool removeMember(String const& key, Value* removed); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); +#endif /// Same as removeMember(String const& key, Value* removed) bool removeMember(const char* begin, const char* end, Value* removed); /** \brief Remove the indexed array element. @@ -549,12 +590,18 @@ class JSON_API Value { */ bool removeIndex(ArrayIndex index, Value* removed); +#ifdef JSONCPP_HAS_STRING_VIEW + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(std::string_view key) const; +#else /// Return true if the object has a member named key. /// \note 'key' must be null-terminated. bool isMember(const char* key) const; /// Return true if the object has a member named key. /// \param key may contain embedded nulls. bool isMember(const String& key) const; +#endif /// Same as isMember(String const& key)const bool isMember(const char* begin, const char* end) const; diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index d9dee50cb..527d716f2 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -17,6 +17,10 @@ #include #include +#ifdef JSONCPP_HAS_STRING_VIEW +#include +#endif + // Provide implementation equivalent of std::snprintf for older _MSC compilers #if defined(_MSC_VER) && _MSC_VER < 1900 #include @@ -420,6 +424,14 @@ Value::Value(const String& value) { value.data(), static_cast(value.length())); } +#ifdef JSONCPP_HAS_STRING_VIEW +Value::Value(std::string_view value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue( + value.data(), static_cast(value.length())); +} +#endif + Value::Value(const StaticString& value) { initBasic(stringValue); value_.string_ = const_cast(value.c_str()); @@ -627,6 +639,21 @@ bool Value::getString(char const** begin, char const** end) const { return true; } +#ifdef JSONCPP_HAS_STRING_VIEW +bool Value::getString(std::string_view* str) const { + if (type() != stringValue) + return false; + if (value_.string_ == nullptr) + return false; + const char* begin; + unsigned length; + decodePrefixedString(this->isAllocated(), this->value_.string_, &length, + &begin); + *str = std::string_view(begin, length); + return true; +} +#endif + String Value::asString() const { switch (type()) { case nullValue: @@ -1108,6 +1135,17 @@ Value* Value::demand(char const* begin, char const* end) { "objectValue or nullValue"); return &resolveReference(begin, end); } +#ifdef JSONCPP_HAS_STRING_VIEW +const Value& Value::operator[](std::string_view key) const { + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) + return nullSingleton(); + return *found; +} +Value& Value::operator[](std::string_view key) { + return resolveReference(key.data(), key.data() + key.length()); +} +#else const Value& Value::operator[](const char* key) const { Value const* found = find(key, key + strlen(key)); if (!found) @@ -1128,6 +1166,7 @@ Value& Value::operator[](const char* key) { Value& Value::operator[](const String& key) { return resolveReference(key.data(), key.data() + key.length()); } +#endif Value& Value::operator[](const StaticString& key) { return resolveReference(key.c_str()); @@ -1167,12 +1206,18 @@ Value Value::get(char const* begin, char const* end, Value const* found = find(begin, end); return !found ? defaultValue : *found; } +#ifdef JSONCPP_HAS_STRING_VIEW +Value Value::get(std::string_view key, const Value& defaultValue) const { + return get(key.data(), key.data() + key.length(), defaultValue); +} +#else Value Value::get(char const* key, Value const& defaultValue) const { return get(key, key + strlen(key), defaultValue); } Value Value::get(String const& key, Value const& defaultValue) const { return get(key.data(), key.data() + key.length(), defaultValue); } +#endif bool Value::removeMember(const char* begin, const char* end, Value* removed) { if (type() != objectValue) { @@ -1188,12 +1233,31 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) { value_.map_->erase(it); return true; } +#ifdef JSONCPP_HAS_STRING_VIEW +bool Value::removeMember(std::string_view key, Value* removed) { + return removeMember(key.data(), key.data() + key.length(), removed); +} +#else bool Value::removeMember(const char* key, Value* removed) { return removeMember(key, key + strlen(key), removed); } bool Value::removeMember(String const& key, Value* removed) { return removeMember(key.data(), key.data() + key.length(), removed); } +#endif + +#ifdef JSONCPP_HAS_STRING_VIEW +void Value::removeMember(std::string_view key) { + JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type() == nullValue) + return; + + CZString actualKey(key.data(), unsigned(key.length()), + CZString::noDuplication); + value_.map_->erase(actualKey); +} +#else void Value::removeMember(const char* key) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::removeMember(): requires objectValue"); @@ -1204,6 +1268,7 @@ void Value::removeMember(const char* key) { value_.map_->erase(actualKey); } void Value::removeMember(const String& key) { removeMember(key.c_str()); } +#endif bool Value::removeIndex(ArrayIndex index, Value* removed) { if (type() != arrayValue) { @@ -1233,12 +1298,18 @@ bool Value::isMember(char const* begin, char const* end) const { Value const* value = find(begin, end); return nullptr != value; } +#ifdef JSONCPP_HAS_STRING_VIEW +bool Value::isMember(std::string_view key) const { + return isMember(key.data(), key.data() + key.length()); +} +#else bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); } bool Value::isMember(String const& key) const { return isMember(key.data(), key.data() + key.length()); } +#endif Value::Members Value::getMemberNames() const { JSON_ASSERT_MESSAGE( From ba004477a6f260dedbe6ef6470b3760192e8d232 Mon Sep 17 00:00:00 2001 From: SwintonStreet Date: Fri, 10 Jan 2025 23:38:47 +0000 Subject: [PATCH 3/5] Added Value::findType with String key (#1574) This adds a convenience function to return a member if it has a specific json type. All isType values are supported. Co-authored-by: Jordan Bayles --- include/json/value.h | 23 ++++++++++ src/lib_json/json_value.cpp | 38 ++++++++++++++++ src/test_lib_json/main.cpp | 86 +++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) diff --git a/include/json/value.h b/include/json/value.h index 307493298..5f6544329 100644 --- a/include/json/value.h +++ b/include/json/value.h @@ -549,6 +549,29 @@ class JSON_API Value { /// Most general and efficient version of isMember()const, get()const, /// and operator[]const Value const* find(const String& key) const; + + /// Calls find and only returns a valid pointer if the type is found + template + Value const* findValue(const String& key) const { + Value const* found = find(key); + if (!found || !(found->*TMemFn)()) + return nullptr; + return found; + } + + Value const* findNull(const String& key) const; + Value const* findBool(const String& key) const; + Value const* findInt(const String& key) const; + Value const* findInt64(const String& key) const; + Value const* findUInt(const String& key) const; + Value const* findUInt64(const String& key) const; + Value const* findIntegral(const String& key) const; + Value const* findDouble(const String& key) const; + Value const* findNumeric(const String& key) const; + Value const* findString(const String& key) const; + Value const* findArray(const String& key) const; + Value const* findObject(const String& key) const; + /// Most general and efficient version of object-mutators. /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 527d716f2..a875d28b2 100644 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -1129,6 +1129,44 @@ Value const* Value::find(char const* begin, char const* end) const { Value const* Value::find(const String& key) const { return find(key.data(), key.data() + key.length()); } + +Value const* Value::findNull(const String& key) const { + return findValue(key); +} +Value const* Value::findBool(const String& key) const { + return findValue(key); +} +Value const* Value::findInt(const String& key) const { + return findValue(key); +} +Value const* Value::findInt64(const String& key) const { + return findValue(key); +} +Value const* Value::findUInt(const String& key) const { + return findValue(key); +} +Value const* Value::findUInt64(const String& key) const { + return findValue(key); +} +Value const* Value::findIntegral(const String& key) const { + return findValue(key); +} +Value const* Value::findDouble(const String& key) const { + return findValue(key); +} +Value const* Value::findNumeric(const String& key) const { + return findValue(key); +} +Value const* Value::findString(const String& key) const { + return findValue(key); +} +Value const* Value::findArray(const String& key) const { + return findValue(key); +} +Value const* Value::findObject(const String& key) const { + return findValue(key); +} + Value* Value::demand(char const* begin, char const* end) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, "in Json::Value::demand(begin, end): requires " diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 5a0ce01ce..60f149d5e 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -76,6 +76,8 @@ struct ValueTest : JsonTest::TestCase { Json::Value float_{0.00390625f}; Json::Value array1_; Json::Value object1_; + Json::Value object2_; + Json::Value object3_; Json::Value emptyString_{""}; Json::Value string1_{"a"}; Json::Value string_{"sometext with space"}; @@ -85,6 +87,34 @@ struct ValueTest : JsonTest::TestCase { ValueTest() { array1_.append(1234); object1_["id"] = 1234; + + // object2 with matching values + object2_["null"] = Json::nullValue; + object2_["bool"] = true; + object2_["int"] = Json::Int{Json::Value::maxInt}; + object2_["int64"] = Json::Int64{Json::Value::maxInt64}; + object2_["uint"] = Json::UInt{Json::Value::maxUInt}; + object2_["uint64"] = Json::UInt64{Json::Value::maxUInt64}; + object2_["integral"] = 1234; + object2_["double"] = 1234.56789; + object2_["numeric"] = 0.12345f; + object2_["string"] = "string"; + object2_["array"] = Json::arrayValue; + object2_["object"] = Json::objectValue; + + // object3 with not matching values + object3_["object"] = Json::nullValue; + object3_["null"] = true; + object3_["bool"] = Json::Int{Json::Value::maxInt}; + object3_["int"] = "not_an_int"; + object3_["int64"] = "not_an_int64"; + object3_["uint"] = "not_an_uint"; + object3_["uin64"] = "not_an_uint64"; + object3_["integral"] = 1234.56789; + object3_["double"] = false; + object3_["numeric"] = "string"; + object3_["string"] = Json::arrayValue; + object3_["array"] = Json::objectValue; } struct IsCheck { @@ -234,6 +264,62 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) { const Json::Value* stringFoundUnknownId = object1_.find(stringUnknownIdKey); JSONTEST_ASSERT_EQUAL(nullptr, stringFoundUnknownId); + // Access through find() + const Json::Value* nullFound = object2_.findNull("null"); + JSONTEST_ASSERT(nullFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::nullValue, *nullFound); + JSONTEST_ASSERT(object3_.findNull("null") == nullptr); + + const Json::Value* boolFound = object2_.findBool("bool"); + JSONTEST_ASSERT(boolFound != nullptr); + JSONTEST_ASSERT_EQUAL(true, *boolFound); + JSONTEST_ASSERT(object3_.findBool("bool") == nullptr); + + const Json::Value* intFound = object2_.findInt("int"); + JSONTEST_ASSERT(intFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::Int{Json::Value::maxInt}, *intFound); + JSONTEST_ASSERT(object3_.findInt("int") == nullptr); + + const Json::Value* int64Found = object2_.findInt64("int64"); + JSONTEST_ASSERT(int64Found != nullptr); + JSONTEST_ASSERT_EQUAL(Json::Int64{Json::Value::maxInt64}, *int64Found); + JSONTEST_ASSERT(object3_.findInt64("int64") == nullptr); + + const Json::Value* uintFound = object2_.findUInt("uint"); + JSONTEST_ASSERT(uintFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::UInt{Json::Value::maxUInt}, *uintFound); + JSONTEST_ASSERT(object3_.findUInt("uint") == nullptr); + + const Json::Value* uint64Found = object2_.findUInt64("uint64"); + JSONTEST_ASSERT(uint64Found != nullptr); + JSONTEST_ASSERT_EQUAL(Json::UInt64{Json::Value::maxUInt64}, *uint64Found); + JSONTEST_ASSERT(object3_.findUInt64("uint64") == nullptr); + + const Json::Value* integralFound = object2_.findIntegral("integral"); + JSONTEST_ASSERT(integralFound != nullptr); + JSONTEST_ASSERT_EQUAL(1234, *integralFound); + JSONTEST_ASSERT(object3_.findIntegral("integral") == nullptr); + + const Json::Value* doubleFound = object2_.findDouble("double"); + JSONTEST_ASSERT(doubleFound != nullptr); + JSONTEST_ASSERT_EQUAL(1234.56789, *doubleFound); + JSONTEST_ASSERT(object3_.findDouble("double") == nullptr); + + const Json::Value* numericFound = object2_.findNumeric("numeric"); + JSONTEST_ASSERT(numericFound != nullptr); + JSONTEST_ASSERT_EQUAL(0.12345f, *numericFound); + JSONTEST_ASSERT(object3_.findNumeric("numeric") == nullptr); + + const Json::Value* stringFound = object2_.findString("string"); + JSONTEST_ASSERT(stringFound != nullptr); + JSONTEST_ASSERT_EQUAL(std::string{"string"}, *stringFound); + JSONTEST_ASSERT(object3_.findString("string") == nullptr); + + const Json::Value* arrayFound = object2_.findArray("array"); + JSONTEST_ASSERT(arrayFound != nullptr); + JSONTEST_ASSERT_EQUAL(Json::arrayValue, *arrayFound); + JSONTEST_ASSERT(object3_.findArray("array") == nullptr); + // Access through demand() const char yetAnotherIdKey[] = "yet another id"; const Json::Value* foundYetAnotherId = From 037752d9a1e48c8b7e5a62ee895a352166df03e3 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:57:16 -0700 Subject: [PATCH 4/5] Set up for Bazel module builds. (#1597) * Set up for Bazel module builds. Note: the MODULE.bazel is copied from https://github.com/bazelbuild/bazel-central-registry/blob/main/modules/jsoncpp/1.9.6/MODULE.bazel * More tweaks to .gitignore --- .gitignore | 4 ++++ CMakeLists.txt | 3 ++- MODULE.bazel | 14 ++++++++++++++ include/json/version.h | 3 ++- meson.build | 3 ++- 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 MODULE.bazel diff --git a/.gitignore b/.gitignore index 9682782fa..69868f413 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,7 @@ compile_commands.json # temps /version + +# Bazel output paths +/bazel-* +/MODULE.bazel.lock diff --git a/CMakeLists.txt b/CMakeLists.txt index 6104c5ce5..5ab9c52a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,12 +55,13 @@ endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") project(jsoncpp - # Note: version must be updated in three places when doing a release. This + # Note: version must be updated in four places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the # correct version. # 1. ./meson.build # 2. ./include/json/version.h # 3. ./CMakeLists.txt + # 4. ./MODULE.bazel # IMPORTANT: also update the PROJECT_SOVERSION!! VERSION 1.9.7 # [.[.[.]]] LANGUAGES CXX) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..03f192dd4 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,14 @@ +module( + name = "jsoncpp", + + # Note: version must be updated in four places when doing a release. This + # annoying process ensures that amalgamate, CMake, and meson all report the + # correct version. + # 1. /meson.build + # 2. /include/json/version.h + # 3. /CMakeLists.txt + # 4. /MODULE.bazel + # IMPORTANT: also update the SOVERSION!! + version = "1.9.7", + compatibility_level = 1, +) diff --git a/include/json/version.h b/include/json/version.h index 42e8780a3..555152c8c 100644 --- a/include/json/version.h +++ b/include/json/version.h @@ -1,12 +1,13 @@ #ifndef JSON_VERSION_H_INCLUDED #define JSON_VERSION_H_INCLUDED -// Note: version must be updated in three places when doing a release. This +// Note: version must be updated in four places when doing a release. This // annoying process ensures that amalgamate, CMake, and meson all report the // correct version. // 1. /meson.build // 2. /include/json/version.h // 3. /CMakeLists.txt +// 4. /MODULE.bazel // IMPORTANT: also update the SOVERSION!! #define JSONCPP_VERSION_STRING "1.9.7" diff --git a/meson.build b/meson.build index 8e8d57e3c..2648c3071 100644 --- a/meson.build +++ b/meson.build @@ -2,12 +2,13 @@ project( 'jsoncpp', 'cpp', - # Note: version must be updated in three places when doing a release. This + # Note: version must be updated in four places when doing a release. This # annoying process ensures that amalgamate, CMake, and meson all report the # correct version. # 1. /meson.build # 2. /include/json/version.h # 3. /CMakeLists.txt + # 4. /MODULE.bazel # IMPORTANT: also update the SOVERSION!! version : '1.9.7', default_options : [ From ca98c98457b1163cca1f7d8db62827c115fec6d1 Mon Sep 17 00:00:00 2001 From: bcsgh <33939446+bcsgh@users.noreply.github.com> Date: Tue, 18 Mar 2025 16:15:37 -0700 Subject: [PATCH 5/5] Add a BUILD.bazel file for //example. (#1602) --- example/BUILD.bazel | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 example/BUILD.bazel diff --git a/example/BUILD.bazel b/example/BUILD.bazel new file mode 100644 index 000000000..38e7dfcf7 --- /dev/null +++ b/example/BUILD.bazel @@ -0,0 +1,33 @@ +cc_binary( + name = "readFromStream_ok", + srcs = ["readFromStream/readFromStream.cpp"], + deps = ["//:jsoncpp"], + args = ["$(location :readFromStream/withComment.json)"], + data = ["readFromStream/withComment.json"], +) + +cc_binary( + name = "readFromStream_err", + srcs = ["readFromStream/readFromStream.cpp"], + deps = ["//:jsoncpp"], + args = ["$(location :readFromStream/errorFormat.json)"], + data = ["readFromStream/errorFormat.json"], +) + +cc_binary( + name = "readFromString", + srcs = ["readFromString/readFromString.cpp"], + deps = ["//:jsoncpp"], +) + +cc_binary( + name = "streamWrite", + srcs = ["streamWrite/streamWrite.cpp"], + deps = ["//:jsoncpp"], +) + +cc_binary( + name = "stringWrite", + srcs = ["stringWrite/stringWrite.cpp"], + deps = ["//:jsoncpp"], +)