From 702b45bb6e3c84fa87c7cf3513b92c1a8c18f3c6 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Tue, 19 Aug 2014 16:03:16 +0200 Subject: [PATCH 1/4] GenericValue: refactoring of operator==/!= By restructuring the call forwarding of the various operator== and operator!= overloads, new overloads can be added by simply adding an additional member operator==. Additionally, the "Ch*" overloads are dropped in favour of an SFINAE version that removes the pointer variants from matching the templated operator== (see also operator=). --- include/rapidjson/document.h | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index a44c0eaf2..532207667 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -619,28 +619,28 @@ class GenericValue { } } - //! Not-equal-to operator - bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } - - //! (Not-)Equal-to operator with const C-string pointer. - friend bool operator==(const GenericValue& lhs, const Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); } - friend bool operator!=(const GenericValue& lhs, const Ch* rhs) { return !(lhs == rhs); } - friend bool operator==(const Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; } - friend bool operator!=(const Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); } - - //! (Not-)Equal-to operator with non-const C-string pointer. - friend bool operator==(const GenericValue& lhs, Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); } - friend bool operator!=(const GenericValue& lhs, Ch* rhs) { return !(lhs == rhs); } - friend bool operator==(Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; } - friend bool operator!=(Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); } - - //! (Not-)Equal-to operator with primitive types. + //! Equal-to operator with const C-string pointer + bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } + + //! Equal-to operator with primitive types /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false */ - template friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); } - template friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); } - template friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; } - template friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); } + template RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer, bool) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + + //! Not-equal-to operator with arbitrary types + /*! \return !(*this == rhs) + */ + template bool operator!=(const T& rhs) const { return !(*this == rhs); } + + //! Equal-to operator with arbitrary types (symmetric version) + /*! \return (rhs == lhs) + */ + template friend bool operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + + //! Not-Equal-to operator with arbitrary types (symmetric version) + /*! \return !(rhs == lhs) + */ + template friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} //!@name Type From 744b4852ff40ad33a0408882a04c5ef121bc9a48 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Tue, 19 Aug 2014 19:38:34 +0200 Subject: [PATCH 2/4] GenericValue: add (optional) support for std::string Some users may want to use RapidJSON with std::string objects. This commits adds an (opt-in) feature to include some basic support. The implementation uses std::basic_string as generic string type. Support currently covers: * construction * comparison No special APIs for AddMember or PushBack have been added, as std::string most probably requires copying (or an explicit StringRef() call). --- include/rapidjson/document.h | 69 ++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 532207667..f14717e7d 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -21,6 +21,8 @@ #ifndef RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ +/*! \file document.h */ + #include "reader.h" #include "internal/strfunc.h" #include // placement new @@ -33,6 +35,26 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#endif +#ifdef RAPIDJSON_HAS_STDSTRING +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#include +#endif // RAPIDJSON_HAS_STDSTRING + #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include "internal/meta.h" #include // std::iterator, std::random_access_iterator_tag @@ -56,6 +78,9 @@ struct GenericMember { GenericValue value; //!< value of member. }; +/////////////////////////////////////////////////////////////////////////////// +// GenericMemberIterator + #ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value @@ -338,6 +363,25 @@ inline GenericStringRef StringRef(const CharType* str, size_t length) return GenericStringRef(str, SizeType(length)); } +#ifdef RAPIDJSON_HAS_STDSTRING +//! Mark a string object as constant string +/*! Mark a string object (e.g. \c std::string) as a "string literal". + This function can be used to avoid copying a string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. +*/ +template +inline GenericStringRef StringRef(const std::basic_string& str) { + return GenericStringRef(str.data(), SizeType(str.size())); +} +#endif + /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -470,6 +514,13 @@ class GenericValue { //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } +#ifdef RAPIDJSON_HAS_STDSTRING + //! Constructor for copy-string from a string object (i.e. do make a copy of string) + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue(const std::basic_string& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } +#endif + //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ @@ -622,6 +673,13 @@ class GenericValue { //! Equal-to operator with const C-string pointer bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } +#ifdef RAPIDJSON_HAS_STDSTRING + //! Equal-to operator with string object + /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } +#endif + //! Equal-to operator with primitive types /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false */ @@ -1207,6 +1265,17 @@ int z = a[0u].GetInt(); // This works too. */ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } +#if RAPIDJSON_HAS_STDSTRING + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), s.size(), allocator); } +#endif + //@} //! Generate events of this value to a Handler. From 2e0b8730a1c34816101b82b7f25cd15aa0a31bde Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Tue, 19 Aug 2014 19:48:50 +0200 Subject: [PATCH 3/4] add tests for RAPIDJSON_HAS_STDSTRING --- test/unittest/valuetest.cpp | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 692f6bc4d..add509a78 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -537,6 +537,44 @@ TEST(Value, String) { s[0] = '\0'; EXPECT_STREQ("World", w.GetString()); EXPECT_EQ(5u, w.GetStringLength()); + +#ifdef RAPIDJSON_HAS_STDSTRING + { + std::string str = "Hello World"; + str[5] = '\0'; + EXPECT_STREQ(str.data(),"Hello"); // embedded '\0' + EXPECT_EQ(str.size(), 11u); + + // no copy + Value vs0(StringRef(str)); + EXPECT_TRUE(vs0.IsString()); + EXPECT_EQ(vs0.GetString(), str.data()); + EXPECT_EQ(vs0.GetStringLength(), str.size()); + TestEqual(vs0, str); + + // do copy + Value vs1(str, allocator); + EXPECT_TRUE(vs1.IsString()); + EXPECT_NE(vs1.GetString(), str.data()); + EXPECT_NE(vs1.GetString(), str); // not equal due to embedded '\0' + EXPECT_EQ(vs1.GetStringLength(), str.size()); + TestEqual(vs1, str); + + // SetString + str = "World"; + vs0.SetNull().SetString(str, allocator); + EXPECT_TRUE(vs0.IsString()); + EXPECT_STREQ(vs0.GetString(), str.c_str()); + EXPECT_EQ(vs0.GetStringLength(), str.size()); + TestEqual(str, vs0); + TestUnequal(str, vs1); + + // vs1 = str; // should not compile + vs1 = StringRef(str); + TestEqual(str, vs1); + TestEqual(vs0, vs1); + } +#endif // RAPIDJSON_HAS_STDSTRING } TEST(Value, Array) { From ae3e12d7dff8c8c18861ddb9746ca755e3a46df1 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Tue, 19 Aug 2014 19:50:07 +0200 Subject: [PATCH 4/4] .travis.yml: include RAPIDJSON_HAS_STDSTRING tests --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cc98e3bd9..433013295 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ env: - CONF=release BITS=32 global: - GITHUB_REPO='miloyip/rapidjson' + - DEFINES='-DRAPIDJSON_HAS_STDSTRING' - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk=" before_install: