Merge pull request #1010 from pah/fixes/817-stringref-null
Improve handling of NULL strings
This commit is contained in:
commit
f624a3037c
@ -308,7 +308,7 @@ struct GenericStringRef {
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
explicit GenericStringRef(const CharType* str)
|
explicit GenericStringRef(const CharType* str)
|
||||||
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
|
: s(str), length(((RAPIDJSON_ASSERT(str != 0)), internal::StrLen(str))) {}
|
||||||
|
|
||||||
//! Create constant string reference from pointer and length
|
//! Create constant string reference from pointer and length
|
||||||
#ifndef __clang__ // -Wdocumentation
|
#ifndef __clang__ // -Wdocumentation
|
||||||
@ -320,7 +320,7 @@ struct GenericStringRef {
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
GenericStringRef(const CharType* str, SizeType len)
|
GenericStringRef(const CharType* str, SizeType len)
|
||||||
: s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
|
: s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
|
||||||
|
|
||||||
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
|
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
|
||||||
|
|
||||||
@ -331,6 +331,9 @@ struct GenericStringRef {
|
|||||||
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
|
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Empty string - used when passing in a NULL pointer
|
||||||
|
static const Ch emptyString[];
|
||||||
|
|
||||||
//! Disallow construction from non-const array
|
//! Disallow construction from non-const array
|
||||||
template<SizeType N>
|
template<SizeType N>
|
||||||
GenericStringRef(CharType (&str)[N]) /* = delete */;
|
GenericStringRef(CharType (&str)[N]) /* = delete */;
|
||||||
@ -338,6 +341,9 @@ private:
|
|||||||
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
|
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename CharType>
|
||||||
|
const CharType GenericStringRef<CharType>::emptyString[] = { CharType() };
|
||||||
|
|
||||||
//! Mark a character pointer as constant string
|
//! Mark a character pointer as constant string
|
||||||
/*! Mark a plain character pointer as a "string literal". This function
|
/*! Mark a plain character pointer as a "string literal". This function
|
||||||
can be used to avoid copying a character string to be referenced as a
|
can be used to avoid copying a character string to be referenced as a
|
||||||
@ -352,7 +358,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
template<typename CharType>
|
template<typename CharType>
|
||||||
inline GenericStringRef<CharType> StringRef(const CharType* str) {
|
inline GenericStringRef<CharType> StringRef(const CharType* str) {
|
||||||
return GenericStringRef<CharType>(str, internal::StrLen(str));
|
return GenericStringRef<CharType>(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Mark a character pointer as constant string
|
//! Mark a character pointer as constant string
|
||||||
@ -1762,7 +1768,7 @@ public:
|
|||||||
\return The value itself for fluent API.
|
\return The value itself for fluent API.
|
||||||
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
|
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
|
||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
|
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }
|
||||||
|
|
||||||
//! Set this value as a string by copying from source string.
|
//! Set this value as a string by copying from source string.
|
||||||
/*! \param s source string.
|
/*! \param s source string.
|
||||||
@ -1770,7 +1776,15 @@ public:
|
|||||||
\return The value itself for fluent API.
|
\return The value itself for fluent API.
|
||||||
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
|
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
|
||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
|
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
|
||||||
|
|
||||||
|
//! Set this value as a string by copying from source string.
|
||||||
|
/*! \param s source string reference
|
||||||
|
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length
|
||||||
|
*/
|
||||||
|
GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
//! Set this value as a string by copying from source string.
|
//! Set this value as a string by copying from source string.
|
||||||
@ -1780,7 +1794,7 @@ public:
|
|||||||
\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
|
\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.
|
\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(), SizeType(s.size()), allocator); }
|
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
@ -117,7 +117,7 @@ public:
|
|||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
#define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u)
|
||||||
|
|
||||||
class Random {
|
class Random {
|
||||||
public:
|
public:
|
||||||
|
@ -857,9 +857,46 @@ TEST(Value, String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Issue 226: Value of string type should not point to NULL
|
// Issue 226: Value of string type should not point to NULL
|
||||||
TEST(Value, SetStringNullException) {
|
TEST(Value, SetStringNull) {
|
||||||
Value v;
|
|
||||||
EXPECT_THROW(v.SetString(0, 0), AssertException);
|
MemoryPoolAllocator<> allocator;
|
||||||
|
const char* nullPtr = 0;
|
||||||
|
{
|
||||||
|
// Construction with string type creates empty string
|
||||||
|
Value v(kStringType);
|
||||||
|
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||||
|
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||||
|
|
||||||
|
// Construction from/setting to null without length not allowed
|
||||||
|
EXPECT_THROW(Value(StringRef(nullPtr)), AssertException);
|
||||||
|
EXPECT_THROW(Value(StringRef(nullPtr), allocator), AssertException);
|
||||||
|
EXPECT_THROW(v.SetString(nullPtr, allocator), AssertException);
|
||||||
|
|
||||||
|
// Non-empty length with null string is not allowed
|
||||||
|
EXPECT_THROW(v.SetString(nullPtr, 17u), AssertException);
|
||||||
|
EXPECT_THROW(v.SetString(nullPtr, 42u, allocator), AssertException);
|
||||||
|
|
||||||
|
// Setting to null string with empty length is allowed
|
||||||
|
v.SetString(nullPtr, 0u);
|
||||||
|
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||||
|
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||||
|
|
||||||
|
v.SetNull();
|
||||||
|
v.SetString(nullPtr, 0u, allocator);
|
||||||
|
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||||
|
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||||
|
}
|
||||||
|
// Construction with null string and empty length is allowed
|
||||||
|
{
|
||||||
|
Value v(nullPtr,0u);
|
||||||
|
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||||
|
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Value v(nullPtr, 0u, allocator);
|
||||||
|
EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
|
||||||
|
EXPECT_EQ(v.GetStringLength(), 0u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename Allocator>
|
template <typename T, typename Allocator>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user