Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GenericValue: add optional support for std::string #107

Merged
merged 4 commits into from
Aug 20, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
105 changes: 87 additions & 18 deletions include/rapidjson/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#ifndef RAPIDJSON_DOCUMENT_H_
#define RAPIDJSON_DOCUMENT_H_

/*! \file document.h */

#include "reader.h"
#include "internal/strfunc.h"
#include <new> // placement new
Expand All @@ -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 <string>
#endif // RAPIDJSON_HAS_STDSTRING

#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include "internal/meta.h"
#include <iterator> // std::iterator, std::random_access_iterator_tag
Expand All @@ -56,6 +78,9 @@ struct GenericMember {
GenericValue<Encoding, Allocator> value; //!< value of member.
};

///////////////////////////////////////////////////////////////////////////////
// GenericMemberIterator

#ifndef RAPIDJSON_NOMEMBERITERATORCLASS

//! (Constant) member iterator for a JSON object value
Expand Down Expand Up @@ -338,6 +363,25 @@ inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length)
return GenericStringRef<CharType>(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<typename CharType>
inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
}
#endif

///////////////////////////////////////////////////////////////////////////////
// GenericValue

Expand Down Expand Up @@ -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<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
#endif

//! Destructor.
/*! Need to destruct elements of array, members of object, or copy-string.
*/
Expand Down Expand Up @@ -619,28 +670,35 @@ class GenericValue {
}
}

//! Not-equal-to operator
bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); }
//! Equal-to operator with const C-string pointer
bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(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); }
#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<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
#endif

//! (Not-)Equal-to operator with primitive types.
//! 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 <typename T> friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); }
template <typename T> friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); }
template <typename T> friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; }
template <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); }
template <typename T> RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>, bool) operator==(const T& rhs) const { return *this == GenericValue(rhs); }

//! Not-equal-to operator with arbitrary types
/*! \return !(*this == rhs)
*/
template <typename T> bool operator!=(const T& rhs) const { return !(*this == rhs); }

//! Equal-to operator with arbitrary types (symmetric version)
/*! \return (rhs == lhs)
*/
template <typename T> 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 <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
//@}

//!@name Type
Expand Down Expand Up @@ -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<Ch>& s, Allocator& allocator) { return SetString(s.data(), s.size(), allocator); }
#endif

//@}

//! Generate events of this value to a Handler.
Expand Down
38 changes: 38 additions & 0 deletions test/unittest/valuetest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down