Merge pull request #57 from pah/cleanup/string-handling
Improved handling of (constant) strings
This commit is contained in:
commit
63de910d16
@ -1990,7 +1990,9 @@ INCLUDE_FILE_PATTERNS =
|
|||||||
# recursively expanded use the := operator instead of the = operator.
|
# recursively expanded use the := operator instead of the = operator.
|
||||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||||
|
|
||||||
PREDEFINED =
|
PREDEFINED = \
|
||||||
|
RAPIDJSON_DOXYGEN_RUNNING \
|
||||||
|
RAPIDJSON_DISABLEIF_RETURN(cond,returntype)=returntype
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
@ -313,6 +313,17 @@ Value o(kObjectType);
|
|||||||
|
|
||||||
This is called move assignment operator in C++11. As RapidJSON supports C++03, it adopts move semantics using assignment operator, and all other modifying function like `AddMember()`, `PushBack()`.
|
This is called move assignment operator in C++11. As RapidJSON supports C++03, it adopts move semantics using assignment operator, and all other modifying function like `AddMember()`, `PushBack()`.
|
||||||
|
|
||||||
|
### Move semantics and temporary values {#TemporaryValues}
|
||||||
|
|
||||||
|
Sometimes, it is convenient to construct a Value in place, before passing it to one of the "moving" functions, like `PushBack()` or `AddMember()`. As temporary objects can't be converted to proper Value references, the convenience function `Move()` is available:
|
||||||
|
|
||||||
|
~~~~~~~~~~cpp
|
||||||
|
Value a(kArrayType);
|
||||||
|
// a.PushBack(Value(42)); // will not compile
|
||||||
|
a.PushBack(Value().SetInt(42)); // fluent API
|
||||||
|
a.PushBack(Value(42).Move()); // same as above
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
## Create String {#CreateString}
|
## Create String {#CreateString}
|
||||||
RapidJSON provide two strategies for storing string.
|
RapidJSON provide two strategies for storing string.
|
||||||
|
|
||||||
@ -339,15 +350,28 @@ In this example, we get the allocator from a `Document` instance. This is a comm
|
|||||||
|
|
||||||
Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length.
|
Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length.
|
||||||
|
|
||||||
Finally, for literal string or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter:
|
Finally, for literal string or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
|
||||||
|
|
||||||
~~~~~~~~~~cpp
|
~~~~~~~~~~cpp
|
||||||
Value s;
|
Value s;
|
||||||
s.SetString("rapidjson", 9); // faster, can contain null character
|
s.SetString("rapidjson"); // can contain null character, length derived at compile time
|
||||||
s.SetString("rapidjson"); // slower, assumes null-terminated
|
|
||||||
s = "rapidjson"; // shortcut, same as above
|
s = "rapidjson"; // shortcut, same as above
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
For plain string pointers, the RapidJSON requires to mark a string as safe before using it without copying. This can be achieved by using the `StringRef` function:
|
||||||
|
|
||||||
|
~~~~~~~~~cpp
|
||||||
|
const char * cstr = getenv("USER");
|
||||||
|
size_t cstr_len = ...; // in case length is available
|
||||||
|
Value s;
|
||||||
|
// s.SetString(cstr); // will not compile
|
||||||
|
s.SetString(StringRef(cstr)); // ok, assume safe lifetime, null-terminated
|
||||||
|
s = StringRef(cstr); // shortcut, same as above
|
||||||
|
s.SetString(StringRef(cstr,cstr_len)); // faster, can contain null character
|
||||||
|
s = StringRef(cstr,cstr_len); // shortcut, same as above
|
||||||
|
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
## Modify Array {#ModifyArray}
|
## Modify Array {#ModifyArray}
|
||||||
Value with array type provides similar APIs as `std::vector`.
|
Value with array type provides similar APIs as `std::vector`.
|
||||||
|
|
||||||
@ -357,7 +381,7 @@ Value with array type provides similar APIs as `std::vector`.
|
|||||||
* `template <typename T> GenericValue& PushBack(T, Allocator&)`
|
* `template <typename T> GenericValue& PushBack(T, Allocator&)`
|
||||||
* `Value& PopBack()`
|
* `Value& PopBack()`
|
||||||
|
|
||||||
Note that, `Reserve(...)` and `PushBack(...)` may allocate memory, therefore requires an allocator.
|
Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator.
|
||||||
|
|
||||||
Here is an example of `PushBack()`:
|
Here is an example of `PushBack()`:
|
||||||
|
|
||||||
@ -372,14 +396,26 @@ for (int i = 5; i <= 10; i++)
|
|||||||
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called fluent interface.
|
Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called _fluent interface_.
|
||||||
|
|
||||||
|
If you want to add a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)) to the array, you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
|
||||||
|
|
||||||
|
~~~~~~~~~~cpp
|
||||||
|
// in-place Value parameter
|
||||||
|
contact.PushBack(Value("copy", document.GetAllocator()).Move(), // copy string
|
||||||
|
document.GetAllocator());
|
||||||
|
|
||||||
|
// explicit parameters
|
||||||
|
Value val("key", document.GetAllocator()); // copy string
|
||||||
|
contact.PushBack(val, document.GetAllocator());
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
## Modify Object {#ModifyObject}
|
## Modify Object {#ModifyObject}
|
||||||
Object is a collection of key-value pairs. Each key must be a string value. The way to manipulating object is to add/remove members:
|
Object is a collection of key-value pairs. Each key must be a string value. The way to manipulating object is to add/remove members:
|
||||||
|
|
||||||
* `Value& AddMember(Value&, Value&, Allocator& allocator)`
|
* `Value& AddMember(Value&, Value&, Allocator& allocator)`
|
||||||
* `Value& AddMember(const Ch*, Value&, Allocator&)`
|
* `Value& AddMember(StringRefType, Value&, Allocator&)`
|
||||||
* `template <typename T> Value& AddMember(const Ch*, T value, Allocator&)`
|
* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
|
||||||
* `bool RemoveMember(const Ch*)`
|
* `bool RemoveMember(const Ch*)`
|
||||||
|
|
||||||
Here is an example.
|
Here is an example.
|
||||||
@ -390,6 +426,22 @@ contact.AddMember("name", "Milo", document.GetAllocator());
|
|||||||
contact.AddMember("married", true, document.GetAllocator());
|
contact.AddMember("married", true, document.GetAllocator());
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
The `StringRefType` used as name parameter assumes the same interface as the `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, as constant key names are very common in JSON objects.
|
||||||
|
|
||||||
|
If you need to create a name from a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)), you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
|
||||||
|
|
||||||
|
~~~~~~~~~~cpp
|
||||||
|
// in-place Value parameter
|
||||||
|
contact.AddMember(Value("copy", document.GetAllocator()).Move(), // copy string
|
||||||
|
Value().Move(), // null value
|
||||||
|
document.GetAllocator());
|
||||||
|
|
||||||
|
// explicit parameters
|
||||||
|
Value key("key", document.GetAllocator()); // copy name string
|
||||||
|
Value val(42); // some value
|
||||||
|
contact.AddMember(key, val, document.GetAllocator());
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
## Deep Copy Value {#DeepCopyValue}
|
## Deep Copy Value {#DeepCopyValue}
|
||||||
If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`.
|
If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`.
|
||||||
|
|
||||||
|
@ -174,6 +174,150 @@ struct GenericMemberIterator<true,Encoding,Allocator> {
|
|||||||
|
|
||||||
#endif // RAPIDJSON_NOMEMBERITERATORCLASS
|
#endif // RAPIDJSON_NOMEMBERITERATORCLASS
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GenericStringRef
|
||||||
|
|
||||||
|
//! Reference to a constant string (not taking a copy)
|
||||||
|
/*!
|
||||||
|
\tparam CharType character type of the string
|
||||||
|
|
||||||
|
This helper class is used to automatically infer constant string
|
||||||
|
references for string literals, especially from \c const \b (!)
|
||||||
|
character arrays.
|
||||||
|
|
||||||
|
The main use is for creating JSON string values without copying the
|
||||||
|
source string via an \ref Allocator. This requires that the referenced
|
||||||
|
string pointers have a sufficient lifetime, which exceeds the lifetime
|
||||||
|
of the associated GenericValue.
|
||||||
|
|
||||||
|
\b Example
|
||||||
|
\code
|
||||||
|
Value v("foo"); // ok, no need to copy & calculate length
|
||||||
|
const char foo[] = "foo";
|
||||||
|
v.SetString(foo); // ok
|
||||||
|
|
||||||
|
const char* bar = foo;
|
||||||
|
// Value x(bar); // not ok, can't rely on bar's lifetime
|
||||||
|
Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
|
||||||
|
Value y(StringRef(bar, 3)); // ok, explicitly pass length
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\see StringRef, GenericValue::SetString
|
||||||
|
*/
|
||||||
|
template<typename CharType>
|
||||||
|
struct GenericStringRef {
|
||||||
|
typedef CharType Ch; //!< character type of the string
|
||||||
|
|
||||||
|
//! Create string reference from \c const character array
|
||||||
|
/*!
|
||||||
|
This constructor implicitly creates a constant string reference from
|
||||||
|
a \c const character array. It has better performance than
|
||||||
|
\ref StringRef(const CharType*) by inferring the string \ref length
|
||||||
|
from the array length, and also supports strings containing null
|
||||||
|
characters.
|
||||||
|
|
||||||
|
\tparam N length of the string, automatically inferred
|
||||||
|
|
||||||
|
\param str Constant character array, lifetime assumed to be longer
|
||||||
|
than the use of the string in e.g. a GenericValue
|
||||||
|
|
||||||
|
\post \ref s == str
|
||||||
|
|
||||||
|
\note Constant complexity.
|
||||||
|
\note There is a hidden, private overload to disallow references to
|
||||||
|
non-const character arrays to be created via this constructor.
|
||||||
|
By this, e.g. function-scope arrays used to be filled via
|
||||||
|
\c snprintf are excluded from consideration.
|
||||||
|
In such cases, the referenced string should be \b copied to the
|
||||||
|
GenericValue instead.
|
||||||
|
*/
|
||||||
|
template<SizeType N>
|
||||||
|
GenericStringRef(const CharType (&str)[N])
|
||||||
|
: s(str), length(N-1) {}
|
||||||
|
|
||||||
|
//! Explicitly create string reference from \c const character pointer
|
||||||
|
/*!
|
||||||
|
This constructor can be used to \b explicitly create a reference to
|
||||||
|
a constant string pointer.
|
||||||
|
|
||||||
|
\see StringRef(const CharType*)
|
||||||
|
|
||||||
|
\param str Constant character pointer, lifetime assumed to be longer
|
||||||
|
than the use of the string in e.g. a GenericValue
|
||||||
|
|
||||||
|
\post \ref s == str
|
||||||
|
|
||||||
|
\note There is a hidden, private overload to disallow references to
|
||||||
|
non-const character arrays to be created via this constructor.
|
||||||
|
By this, e.g. function-scope arrays used to be filled via
|
||||||
|
\c snprintf are excluded from consideration.
|
||||||
|
In such cases, the referenced string should be \b copied to the
|
||||||
|
GenericValue instead.
|
||||||
|
*/
|
||||||
|
explicit GenericStringRef(const CharType* str)
|
||||||
|
: s(str), length(internal::StrLen(str)){}
|
||||||
|
|
||||||
|
//! Create constant string reference from pointer and length
|
||||||
|
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
|
||||||
|
\param len length of the string, excluding the trailing NULL terminator
|
||||||
|
|
||||||
|
\post \ref s == str && \ref length == len
|
||||||
|
\note Constant complexity.
|
||||||
|
*/
|
||||||
|
GenericStringRef(const CharType* str, SizeType len)
|
||||||
|
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
|
||||||
|
|
||||||
|
//! implicit conversion to plain CharType pointer
|
||||||
|
operator const Ch *() const { return s; }
|
||||||
|
|
||||||
|
const Ch* const s; //!< plain CharType pointer
|
||||||
|
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Disallow copy-assignment
|
||||||
|
GenericStringRef operator=(const GenericStringRef&);
|
||||||
|
//! Disallow construction from non-const array
|
||||||
|
template<SizeType N>
|
||||||
|
GenericStringRef(CharType (&str)[N]) /* = delete */;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Mark a character pointer as constant string
|
||||||
|
/*! 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
|
||||||
|
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
|
||||||
|
|
||||||
|
\see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
|
||||||
|
*/
|
||||||
|
template<typename CharType>
|
||||||
|
inline GenericStringRef<CharType> StringRef(const CharType* str) {
|
||||||
|
return GenericStringRef<CharType>(str, internal::StrLen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Mark a character pointer as constant string
|
||||||
|
/*! 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
|
||||||
|
value in a JSON GenericValue object, if the string's lifetime is known
|
||||||
|
to be valid long enough.
|
||||||
|
|
||||||
|
This version has better performance with supplied length, and also
|
||||||
|
supports string containing null characters.
|
||||||
|
|
||||||
|
\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
|
||||||
|
\param length The length of source string.
|
||||||
|
\return GenericStringRef string reference object
|
||||||
|
\relatesalso GenericStringRef
|
||||||
|
*/
|
||||||
|
template<typename CharType>
|
||||||
|
inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
|
||||||
|
return GenericStringRef<CharType>(str, SizeType(length));
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// GenericValue
|
// GenericValue
|
||||||
|
|
||||||
@ -196,6 +340,7 @@ public:
|
|||||||
typedef Encoding EncodingType; //!< Encoding type from template parameter.
|
typedef Encoding EncodingType; //!< Encoding type from template parameter.
|
||||||
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
|
||||||
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
|
||||||
|
typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string
|
||||||
typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
|
typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
|
||||||
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
|
||||||
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
|
||||||
@ -207,8 +352,8 @@ public:
|
|||||||
//! Default constructor creates a null value.
|
//! Default constructor creates a null value.
|
||||||
GenericValue() : data_(), flags_(kNullFlag) {}
|
GenericValue() : data_(), flags_(kNullFlag) {}
|
||||||
|
|
||||||
//! Copy constructor is not permitted.
|
|
||||||
private:
|
private:
|
||||||
|
//! Copy constructor is not permitted.
|
||||||
GenericValue(const GenericValue& rhs);
|
GenericValue(const GenericValue& rhs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -231,14 +376,25 @@ public:
|
|||||||
/*! Creates a copy of a Value by using the given Allocator
|
/*! Creates a copy of a Value by using the given Allocator
|
||||||
\tparam SourceAllocator allocator of \c rhs
|
\tparam SourceAllocator allocator of \c rhs
|
||||||
\param rhs Value to copy from (read-only)
|
\param rhs Value to copy from (read-only)
|
||||||
\param allocator Allocator to use for copying
|
\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
|
||||||
\see CopyFrom()
|
\see CopyFrom()
|
||||||
*/
|
*/
|
||||||
template< typename SourceAllocator >
|
template< typename SourceAllocator >
|
||||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator & allocator);
|
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator & allocator);
|
||||||
|
|
||||||
//! Constructor for boolean value.
|
//! Constructor for boolean value.
|
||||||
explicit GenericValue(bool b) : data_(), flags_(b ? kTrueFlag : kFalseFlag) {}
|
/*! \param b Boolean value
|
||||||
|
\note This constructor is limited to \em real boolean values and rejects
|
||||||
|
implicitly converted types like arbitrary pointers. Use an explicit cast
|
||||||
|
to \c bool, if you want to construct a boolean JSON value in such cases.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
|
||||||
|
template <typename T>
|
||||||
|
explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>)))
|
||||||
|
#else
|
||||||
|
explicit GenericValue(bool b)
|
||||||
|
#endif
|
||||||
|
: data_(), flags_(b ? kTrueFlag : kFalseFlag) {}
|
||||||
|
|
||||||
//! Constructor for int value.
|
//! Constructor for int value.
|
||||||
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) {
|
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) {
|
||||||
@ -283,16 +439,16 @@ public:
|
|||||||
explicit GenericValue(double d) : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
explicit GenericValue(double d) : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
|
||||||
|
|
||||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||||
GenericValue(const Ch* s, SizeType length) : data_(), flags_() { SetStringRaw(s, length); }
|
GenericValue(const Ch* s, SizeType length) : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
|
||||||
|
|
||||||
//! Constructor for constant string (i.e. do not make a copy of string)
|
//! Constructor for constant string (i.e. do not make a copy of string)
|
||||||
explicit GenericValue(const Ch* s) : data_(), flags_() { SetStringRaw(s, internal::StrLen(s)); }
|
explicit GenericValue(StringRefType s) : data_(), flags_() { SetStringRaw(s); }
|
||||||
|
|
||||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||||
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(s, length, allocator); }
|
GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
|
||||||
|
|
||||||
//! Constructor for copy-string (i.e. do make a copy of string)
|
//! Constructor for copy-string (i.e. do make a copy of string)
|
||||||
GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(s, internal::StrLen(s), allocator); }
|
GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
|
||||||
|
|
||||||
//! Destructor.
|
//! Destructor.
|
||||||
/*! Need to destruct elements of array, members of object, or copy-string.
|
/*! Need to destruct elements of array, members of object, or copy-string.
|
||||||
@ -339,12 +495,30 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Assignment of constant string reference (no copy)
|
||||||
|
/*! \param str Constant string reference to be assigned
|
||||||
|
\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
|
||||||
|
\see GenericStringRef, operator=(T)
|
||||||
|
*/
|
||||||
|
GenericValue& operator=(StringRefType str) {
|
||||||
|
return (*this).template operator=<StringRefType>(str);
|
||||||
|
}
|
||||||
|
|
||||||
//! Assignment with primitive types.
|
//! Assignment with primitive types.
|
||||||
/*! \tparam T Either Type, int, unsigned, int64_t, uint64_t, const Ch*
|
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
|
||||||
\param value The value to be assigned.
|
\param value The value to be assigned.
|
||||||
|
|
||||||
|
\note The source type \c T explicitly disallows all pointer types,
|
||||||
|
especially (\c const) \ref Ch*. This helps avoiding implicitly
|
||||||
|
referencing character strings with insufficient lifetime, use
|
||||||
|
\ref SetString(const Ch*, Allocator&) (for copying) or
|
||||||
|
\ref StringRef() (to explicitly mark the pointer as constant) instead.
|
||||||
|
All other pointer types would implicitly convert to \c bool,
|
||||||
|
use \ref SetBool() instead.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
GenericValue& operator=(T value) {
|
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
||||||
|
operator=(T value) {
|
||||||
this->~GenericValue();
|
this->~GenericValue();
|
||||||
new (this) GenericValue(value);
|
new (this) GenericValue(value);
|
||||||
return *this;
|
return *this;
|
||||||
@ -377,6 +551,9 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Prepare Value for move semantics
|
||||||
|
/*! \return *this */
|
||||||
|
GenericValue& Move() { return *this; }
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//!@name Type
|
//!@name Type
|
||||||
@ -410,6 +587,8 @@ public:
|
|||||||
//@{
|
//@{
|
||||||
|
|
||||||
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
|
bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
|
||||||
|
//!< Set boolean value
|
||||||
|
/*! \post IsBool() == true */
|
||||||
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
|
GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
@ -418,6 +597,7 @@ public:
|
|||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Set this value as an empty object.
|
//! Set this value as an empty object.
|
||||||
|
/*! \post IsObject() == true */
|
||||||
GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
|
GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
|
||||||
|
|
||||||
//! Get the value associated with the name.
|
//! Get the value associated with the name.
|
||||||
@ -428,7 +608,7 @@ public:
|
|||||||
A better approach is to use the now public FindMember().
|
A better approach is to use the now public FindMember().
|
||||||
*/
|
*/
|
||||||
GenericValue& operator[](const Ch* name) {
|
GenericValue& operator[](const Ch* name) {
|
||||||
GenericValue n(name, internal::StrLen(name));
|
GenericValue n(StringRef(name));
|
||||||
return (*this)[n];
|
return (*this)[n];
|
||||||
}
|
}
|
||||||
const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
|
const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||||
@ -481,7 +661,7 @@ public:
|
|||||||
\c std::map, this has been changed to MemberEnd() now.
|
\c std::map, this has been changed to MemberEnd() now.
|
||||||
*/
|
*/
|
||||||
MemberIterator FindMember(const Ch* name) {
|
MemberIterator FindMember(const Ch* name) {
|
||||||
GenericValue n(name, internal::StrLen(name));
|
GenericValue n(StringRef(name));
|
||||||
return FindMember(n);
|
return FindMember(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,9 +684,11 @@ public:
|
|||||||
//! Add a member (name-value pair) to the object.
|
//! Add a member (name-value pair) to the object.
|
||||||
/*! \param name A string value as name of member.
|
/*! \param name A string value as name of member.
|
||||||
\param value Value of any type.
|
\param value Value of any type.
|
||||||
\param allocator Allocator for reallocating memory.
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
\return The value itself for fluent API.
|
\return The value itself for fluent API.
|
||||||
\note The ownership of name and value will be transfered to this object if success.
|
\note The ownership of \c name and \c value will be transferred to this object on success.
|
||||||
|
\pre IsObject() && name.IsString()
|
||||||
|
\post name.IsNull() && value.IsNull()
|
||||||
*/
|
*/
|
||||||
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
|
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
|
||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
@ -530,19 +712,53 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericValue& AddMember(const Ch* name, Allocator& nameAllocator, GenericValue& value, Allocator& allocator) {
|
//! Add a member (name-value pair) to the object.
|
||||||
GenericValue n(name, internal::StrLen(name), nameAllocator);
|
/*! \param name A constant string reference as name of member.
|
||||||
|
\param value Value of any type.
|
||||||
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\note The ownership of \c value will be transferred to this object on success.
|
||||||
|
\pre IsObject()
|
||||||
|
\post value.IsNull()
|
||||||
|
*/
|
||||||
|
GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
|
||||||
|
GenericValue n(name);
|
||||||
return AddMember(n, value, allocator);
|
return AddMember(n, value, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericValue& AddMember(const Ch* name, GenericValue& value, Allocator& allocator) {
|
//! Add a constant string value as member (name-value pair) to the object.
|
||||||
GenericValue n(name, internal::StrLen(name));
|
/*! \param name A constant string reference as name of member.
|
||||||
return AddMember(n, value, allocator);
|
\param value constant string reference as value of member.
|
||||||
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\pre IsObject()
|
||||||
|
\note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
|
||||||
|
*/
|
||||||
|
GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
|
||||||
|
GenericValue v(value);
|
||||||
|
return AddMember(name, v, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Add any primitive value as member (name-value pair) to the object.
|
||||||
|
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
|
||||||
|
\param name A constant string reference as name of member.
|
||||||
|
\param value Value of primitive type \c T as value of member
|
||||||
|
\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\pre IsObject()
|
||||||
|
|
||||||
|
\note The source type \c T explicitly disallows all pointer types,
|
||||||
|
especially (\c const) \ref Ch*. This helps avoiding implicitly
|
||||||
|
referencing character strings with insufficient lifetime, use
|
||||||
|
\ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
|
||||||
|
AddMember(StringRefType, StringRefType, Allocator&).
|
||||||
|
All other pointer types would implicitly convert to \c bool,
|
||||||
|
use an explicit cast instead, if needed.
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
GenericValue& AddMember(const Ch* name, T value, Allocator& allocator) {
|
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
||||||
GenericValue n(name, internal::StrLen(name));
|
AddMember(StringRefType name, T value, Allocator& allocator) {
|
||||||
|
GenericValue n(name);
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
return AddMember(n, v, allocator);
|
return AddMember(n, v, allocator);
|
||||||
}
|
}
|
||||||
@ -553,7 +769,7 @@ public:
|
|||||||
\note Removing member is implemented by moving the last member. So the ordering of members is changed.
|
\note Removing member is implemented by moving the last member. So the ordering of members is changed.
|
||||||
*/
|
*/
|
||||||
bool RemoveMember(const Ch* name) {
|
bool RemoveMember(const Ch* name) {
|
||||||
GenericValue n(name, internal::StrLen(name));
|
GenericValue n(StringRef(name));
|
||||||
return RemoveMember(n);
|
return RemoveMember(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,6 +815,7 @@ public:
|
|||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Set this value as an empty array.
|
//! Set this value as an empty array.
|
||||||
|
/*! \post IsArray == true */
|
||||||
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
|
GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
|
||||||
|
|
||||||
//! Get the number of elements in array.
|
//! Get the number of elements in array.
|
||||||
@ -645,7 +862,7 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
|
|
||||||
//! Request the array to have enough capacity to store elements.
|
//! Request the array to have enough capacity to store elements.
|
||||||
/*! \param newCapacity The capacity that the array at least need to have.
|
/*! \param newCapacity The capacity that the array at least need to have.
|
||||||
\param allocator The allocator for allocating memory. It must be the same one use previously.
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
\return The value itself for fluent API.
|
\return The value itself for fluent API.
|
||||||
*/
|
*/
|
||||||
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
|
||||||
@ -657,12 +874,14 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Append a value at the end of the array.
|
//! Append a GenericValue at the end of the array.
|
||||||
/*! \param value The value to be appended.
|
/*! \param value Value to be appended.
|
||||||
\param allocator The allocator for allocating memory. It must be the same one use previously.
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
\return The value itself for fluent API.
|
\pre IsArray() == true
|
||||||
\note The ownership of the value will be transfered to this object if success.
|
\post value.IsNull() == true
|
||||||
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
|
\return The value itself for fluent API.
|
||||||
|
\note The ownership of \c value will be transferred to this array on success.
|
||||||
|
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
|
||||||
*/
|
*/
|
||||||
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
|
||||||
RAPIDJSON_ASSERT(IsArray());
|
RAPIDJSON_ASSERT(IsArray());
|
||||||
@ -672,8 +891,37 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Append a constant string reference at the end of the array.
|
||||||
|
/*! \param value Constant string reference to be appended.
|
||||||
|
\param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\pre IsArray() == true
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
|
||||||
|
\see GenericStringRef
|
||||||
|
*/
|
||||||
|
GenericValue& PushBack(StringRefType value, Allocator& allocator) {
|
||||||
|
return (*this).template PushBack<StringRefType>(value, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Append a primitive value at the end of the array(.)
|
||||||
|
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
|
||||||
|
\param value Value of primitive type T to be appended.
|
||||||
|
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
|
||||||
|
\pre IsArray() == true
|
||||||
|
\return The value itself for fluent API.
|
||||||
|
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
|
||||||
|
|
||||||
|
\note The source type \c T explicitly disallows all pointer types,
|
||||||
|
especially (\c const) \ref Ch*. This helps avoiding implicitly
|
||||||
|
referencing character strings with insufficient lifetime, use
|
||||||
|
\ref PushBack(GenericValue&, Allocator&) or \ref
|
||||||
|
PushBack(StringRefType, Allocator&).
|
||||||
|
All other pointer types would implicitly convert to \c bool,
|
||||||
|
use an explicit cast instead, if needed.
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
GenericValue& PushBack(T value, Allocator& allocator) {
|
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
||||||
|
PushBack(T value, Allocator& allocator) {
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
return PushBack(v, allocator);
|
return PushBack(v, allocator);
|
||||||
}
|
}
|
||||||
@ -727,30 +975,35 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
\param s source string pointer.
|
\param s source string pointer.
|
||||||
\param length The length of source string, excluding the trailing null terminator.
|
\param length The length of source string, excluding the trailing null terminator.
|
||||||
\return The value itself for fluent API.
|
\return The value itself for fluent API.
|
||||||
|
\post IsString() == true && GetString() == s && GetStringLength() == length
|
||||||
|
\see SetString(StringRefType)
|
||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s, SizeType length) { this->~GenericValue(); SetStringRaw(s, length); return *this; }
|
GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
|
||||||
|
|
||||||
//! Set this value as a string without copying source string.
|
//! Set this value as a string without copying source string.
|
||||||
/*! \param s source string pointer.
|
/*! \param s source string reference
|
||||||
\return The value itself for fluent API.
|
\return The value itself for fluent API.
|
||||||
|
\post IsString() == true && GetString() == s && GetStringLength() == s.length
|
||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s) { return SetString(s, internal::StrLen(s)); }
|
GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
|
||||||
|
|
||||||
//! Set this value as a string by copying from source string.
|
//! Set this value as a string by copying from source string.
|
||||||
/*! This version has better performance with supplied length, and also support string containing null character.
|
/*! This version has better performance with supplied length, and also support string containing null character.
|
||||||
\param s source string.
|
\param s source string.
|
||||||
\param length The length of source string, excluding the trailing null terminator.
|
\param length The length of source string, excluding the trailing null terminator.
|
||||||
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
|
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
|
||||||
\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
|
||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, length, allocator); return *this; }
|
GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
|
||||||
|
|
||||||
//! 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.
|
||||||
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
|
\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
|
||||||
\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
|
||||||
*/
|
*/
|
||||||
GenericValue& SetString(const Ch* s, Allocator& allocator) { SetString(s, internal::StrLen(s), allocator); return *this; }
|
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
@ -906,21 +1159,19 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as constant string, without calling destructor.
|
//! Initialize this value as constant string, without calling destructor.
|
||||||
void SetStringRaw(const Ch* s, SizeType length) {
|
void SetStringRaw(StringRefType s) {
|
||||||
RAPIDJSON_ASSERT(s != NULL);
|
|
||||||
flags_ = kConstStringFlag;
|
flags_ = kConstStringFlag;
|
||||||
data_.s.str = s;
|
data_.s.str = s;
|
||||||
data_.s.length = length;
|
data_.s.length = s.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Initialize this value as copy string with initial data, without calling destructor.
|
//! Initialize this value as copy string with initial data, without calling destructor.
|
||||||
void SetStringRaw(const Ch* s, SizeType length, Allocator& allocator) {
|
void SetStringRaw(StringRefType s, Allocator& allocator) {
|
||||||
RAPIDJSON_ASSERT(s != NULL);
|
|
||||||
flags_ = kCopyStringFlag;
|
flags_ = kCopyStringFlag;
|
||||||
data_.s.str = (Ch *)allocator.Malloc((length + 1) * sizeof(Ch));
|
data_.s.str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
|
||||||
data_.s.length = length;
|
data_.s.length = s.length;
|
||||||
memcpy(const_cast<Ch*>(data_.s.str), s, length * sizeof(Ch));
|
memcpy(const_cast<Ch*>(data_.s.str), s, s.length * sizeof(Ch));
|
||||||
const_cast<Ch*>(data_.s.str)[length] = '\0';
|
const_cast<Ch*>(data_.s.str)[s.length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Assignment without calling destructor
|
//! Assignment without calling destructor
|
||||||
|
@ -24,11 +24,14 @@ struct SelectIf : SelectIfCond<Condition::Value,T1,T2> {};
|
|||||||
template <bool Constify, typename T>
|
template <bool Constify, typename T>
|
||||||
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
|
|
||||||
template <typename T, typename U> struct IsSame { enum { Value = false }; };
|
template <typename T, typename U> struct IsSame : FalseType {};
|
||||||
template <typename T> struct IsSame<T,T> { enum { Value = true }; };
|
template <typename T> struct IsSame<T,T> : TrueType {};
|
||||||
|
|
||||||
template <typename T> struct IsConst { enum { Value = false }; };
|
template <typename T> struct IsConst : FalseType {};
|
||||||
template <typename T> struct IsConst<const T> { enum { Value = true }; };
|
template <typename T> struct IsConst<const T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename T> struct IsPointer : FalseType {};
|
||||||
|
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||||
|
|
||||||
template <typename CT, typename T>
|
template <typename CT, typename T>
|
||||||
struct IsMoreConst {
|
struct IsMoreConst {
|
||||||
@ -64,6 +67,9 @@ template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef
|
|||||||
typename ::rapidjson::internal::EnableIf \
|
typename ::rapidjson::internal::EnableIf \
|
||||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace rapidjson
|
} // namespace rapidjson
|
||||||
//@endcond
|
//@endcond
|
||||||
|
@ -23,6 +23,25 @@ TEST(Value, assignment_operator) {
|
|||||||
y = x;
|
y = x;
|
||||||
EXPECT_TRUE(x.IsNull()); // move semantic
|
EXPECT_TRUE(x.IsNull()); // move semantic
|
||||||
EXPECT_EQ(1234, y.GetInt());
|
EXPECT_EQ(1234, y.GetInt());
|
||||||
|
|
||||||
|
y = 5678;
|
||||||
|
EXPECT_TRUE(y.IsInt());
|
||||||
|
EXPECT_EQ(5678, y.GetInt());
|
||||||
|
|
||||||
|
x = "Hello";
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_STREQ(x.GetString(),"Hello");
|
||||||
|
|
||||||
|
y = StringRef(x.GetString(),x.GetStringLength());
|
||||||
|
EXPECT_TRUE(y.IsString());
|
||||||
|
EXPECT_EQ(y.GetString(),x.GetString());
|
||||||
|
EXPECT_EQ(y.GetStringLength(),x.GetStringLength());
|
||||||
|
|
||||||
|
static char mstr[] = "mutable";
|
||||||
|
// y = mstr; // should not compile
|
||||||
|
y = StringRef(mstr);
|
||||||
|
EXPECT_TRUE(y.IsString());
|
||||||
|
EXPECT_EQ(y.GetString(),mstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
@ -350,8 +369,8 @@ TEST(Value, Double) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(Value, String) {
|
TEST(Value, String) {
|
||||||
// Constructor with const string
|
// Construction with const string
|
||||||
Value x("Hello", 5);
|
Value x("Hello", 5); // literal
|
||||||
EXPECT_EQ(kStringType, x.GetType());
|
EXPECT_EQ(kStringType, x.GetType());
|
||||||
EXPECT_TRUE(x.IsString());
|
EXPECT_TRUE(x.IsString());
|
||||||
EXPECT_STREQ("Hello", x.GetString());
|
EXPECT_STREQ("Hello", x.GetString());
|
||||||
@ -365,9 +384,41 @@ TEST(Value, String) {
|
|||||||
EXPECT_FALSE(x.IsObject());
|
EXPECT_FALSE(x.IsObject());
|
||||||
EXPECT_FALSE(x.IsArray());
|
EXPECT_FALSE(x.IsArray());
|
||||||
|
|
||||||
|
static const char cstr[] = "World"; // const array
|
||||||
|
Value(cstr).Swap(x);
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_EQ(x.GetString(), cstr);
|
||||||
|
EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1);
|
||||||
|
|
||||||
|
static char mstr[] = "Howdy"; // non-const array
|
||||||
|
// Value(mstr).Swap(x); // should not compile
|
||||||
|
Value(StringRef(mstr)).Swap(x);
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_EQ(x.GetString(), mstr);
|
||||||
|
EXPECT_EQ(x.GetStringLength(), sizeof(mstr)-1);
|
||||||
|
strncpy(mstr,"Hello", sizeof(mstr));
|
||||||
|
EXPECT_STREQ(x.GetString(), "Hello");
|
||||||
|
|
||||||
|
const char* pstr = cstr;
|
||||||
|
//Value(pstr).Swap(x); // should not compile
|
||||||
|
Value(StringRef(pstr)).Swap(x);
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_EQ(x.GetString(), cstr);
|
||||||
|
EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1);
|
||||||
|
|
||||||
|
char* mpstr = mstr;
|
||||||
|
Value(StringRef(mpstr,sizeof(mstr)-1)).Swap(x);
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
|
EXPECT_EQ(x.GetString(), mstr);
|
||||||
|
EXPECT_EQ(x.GetStringLength(), 5u);
|
||||||
|
EXPECT_STREQ(x.GetString(), "Hello");
|
||||||
|
|
||||||
// Constructor with copy string
|
// Constructor with copy string
|
||||||
MemoryPoolAllocator<> allocator;
|
MemoryPoolAllocator<> allocator;
|
||||||
Value c(x.GetString(), x.GetStringLength(), allocator);
|
Value c(x.GetString(), x.GetStringLength(), allocator);
|
||||||
|
EXPECT_NE(x.GetString(), c.GetString());
|
||||||
|
EXPECT_EQ(x.GetStringLength(), c.GetStringLength());
|
||||||
|
EXPECT_STREQ(x.GetString(), c.GetString());
|
||||||
//x.SetString("World");
|
//x.SetString("World");
|
||||||
x.SetString("World", 5);
|
x.SetString("World", 5);
|
||||||
EXPECT_STREQ("Hello", c.GetString());
|
EXPECT_STREQ("Hello", c.GetString());
|
||||||
@ -381,11 +432,31 @@ TEST(Value, String) {
|
|||||||
|
|
||||||
// SetConsttring()
|
// SetConsttring()
|
||||||
Value z;
|
Value z;
|
||||||
//z.SetString("Hello");
|
z.SetString("Hello");
|
||||||
|
EXPECT_TRUE(x.IsString());
|
||||||
z.SetString("Hello", 5);
|
z.SetString("Hello", 5);
|
||||||
EXPECT_STREQ("Hello", z.GetString());
|
EXPECT_STREQ("Hello", z.GetString());
|
||||||
|
EXPECT_STREQ("Hello", z.GetString());
|
||||||
EXPECT_EQ(5u, z.GetStringLength());
|
EXPECT_EQ(5u, z.GetStringLength());
|
||||||
|
|
||||||
|
z.SetString("Hello");
|
||||||
|
EXPECT_TRUE(z.IsString());
|
||||||
|
EXPECT_STREQ("Hello", z.GetString());
|
||||||
|
|
||||||
|
//z.SetString(mstr); // should not compile
|
||||||
|
//z.SetString(pstr); // should not compile
|
||||||
|
z.SetString(StringRef(mstr));
|
||||||
|
EXPECT_TRUE(z.IsString());
|
||||||
|
EXPECT_STREQ(z.GetString(), mstr);
|
||||||
|
|
||||||
|
z.SetString(cstr);
|
||||||
|
EXPECT_TRUE(z.IsString());
|
||||||
|
EXPECT_EQ(cstr, z.GetString());
|
||||||
|
|
||||||
|
z = cstr;
|
||||||
|
EXPECT_TRUE(z.IsString());
|
||||||
|
EXPECT_EQ(cstr, z.GetString());
|
||||||
|
|
||||||
// SetString()
|
// SetString()
|
||||||
char s[] = "World";
|
char s[] = "World";
|
||||||
Value w;
|
Value w;
|
||||||
@ -424,11 +495,13 @@ TEST(Value, Array) {
|
|||||||
x.PushBack(v, allocator);
|
x.PushBack(v, allocator);
|
||||||
v.SetInt(123);
|
v.SetInt(123);
|
||||||
x.PushBack(v, allocator);
|
x.PushBack(v, allocator);
|
||||||
|
//x.PushBack((const char*)"foo", allocator); // should not compile
|
||||||
|
x.PushBack("foo", allocator);
|
||||||
|
|
||||||
EXPECT_FALSE(x.Empty());
|
EXPECT_FALSE(x.Empty());
|
||||||
EXPECT_EQ(4u, x.Size());
|
EXPECT_EQ(5u, x.Size());
|
||||||
EXPECT_FALSE(y.Empty());
|
EXPECT_FALSE(y.Empty());
|
||||||
EXPECT_EQ(4u, y.Size());
|
EXPECT_EQ(5u, y.Size());
|
||||||
EXPECT_TRUE(x[SizeType(0)].IsNull());
|
EXPECT_TRUE(x[SizeType(0)].IsNull());
|
||||||
EXPECT_TRUE(x[1u].IsTrue());
|
EXPECT_TRUE(x[1u].IsTrue());
|
||||||
EXPECT_TRUE(x[2u].IsFalse());
|
EXPECT_TRUE(x[2u].IsFalse());
|
||||||
@ -439,6 +512,8 @@ TEST(Value, Array) {
|
|||||||
EXPECT_TRUE(y[2u].IsFalse());
|
EXPECT_TRUE(y[2u].IsFalse());
|
||||||
EXPECT_TRUE(y[3u].IsInt());
|
EXPECT_TRUE(y[3u].IsInt());
|
||||||
EXPECT_EQ(123, y[3u].GetInt());
|
EXPECT_EQ(123, y[3u].GetInt());
|
||||||
|
EXPECT_TRUE(y[4u].IsString());
|
||||||
|
EXPECT_STREQ("foo", y[4u].GetString());
|
||||||
|
|
||||||
// iterator
|
// iterator
|
||||||
Value::ValueIterator itr = x.Begin();
|
Value::ValueIterator itr = x.Begin();
|
||||||
@ -454,6 +529,10 @@ TEST(Value, Array) {
|
|||||||
EXPECT_TRUE(itr != x.End());
|
EXPECT_TRUE(itr != x.End());
|
||||||
EXPECT_TRUE(itr->IsInt());
|
EXPECT_TRUE(itr->IsInt());
|
||||||
EXPECT_EQ(123, itr->GetInt());
|
EXPECT_EQ(123, itr->GetInt());
|
||||||
|
++itr;
|
||||||
|
EXPECT_TRUE(itr != x.End());
|
||||||
|
EXPECT_TRUE(itr->IsString());
|
||||||
|
EXPECT_STREQ("foo", itr->GetString());
|
||||||
|
|
||||||
// const iterator
|
// const iterator
|
||||||
Value::ConstValueIterator citr = y.Begin();
|
Value::ConstValueIterator citr = y.Begin();
|
||||||
@ -469,13 +548,18 @@ TEST(Value, Array) {
|
|||||||
EXPECT_TRUE(citr != y.End());
|
EXPECT_TRUE(citr != y.End());
|
||||||
EXPECT_TRUE(citr->IsInt());
|
EXPECT_TRUE(citr->IsInt());
|
||||||
EXPECT_EQ(123, citr->GetInt());
|
EXPECT_EQ(123, citr->GetInt());
|
||||||
|
++citr;
|
||||||
|
EXPECT_TRUE(citr != y.End());
|
||||||
|
EXPECT_TRUE(citr->IsString());
|
||||||
|
EXPECT_STREQ("foo", citr->GetString());
|
||||||
|
|
||||||
// PopBack()
|
// PopBack()
|
||||||
x.PopBack();
|
x.PopBack();
|
||||||
EXPECT_EQ(3u, x.Size());
|
EXPECT_EQ(4u, x.Size());
|
||||||
EXPECT_TRUE(y[SizeType(0)].IsNull());
|
EXPECT_TRUE(y[SizeType(0)].IsNull());
|
||||||
EXPECT_TRUE(y[1].IsTrue());
|
EXPECT_TRUE(y[1u].IsTrue());
|
||||||
EXPECT_TRUE(y[2].IsFalse());
|
EXPECT_TRUE(y[2u].IsFalse());
|
||||||
|
EXPECT_TRUE(y[3u].IsInt());
|
||||||
|
|
||||||
// Clear()
|
// Clear()
|
||||||
x.Clear();
|
x.Clear();
|
||||||
@ -502,16 +586,34 @@ TEST(Value, Object) {
|
|||||||
EXPECT_TRUE(y.IsObject());
|
EXPECT_TRUE(y.IsObject());
|
||||||
|
|
||||||
// AddMember()
|
// AddMember()
|
||||||
Value name("A", 1);
|
x.AddMember("A", "Apple", allocator);
|
||||||
Value value("Apple", 5);
|
|
||||||
x.AddMember(name, value, allocator);
|
Value value("Banana", 6);
|
||||||
//name.SetString("B");
|
x.AddMember("B", "Banana", allocator);
|
||||||
name.SetString("B", 1);
|
|
||||||
//value.SetString("Banana");
|
// AddMember<T>(StringRefType, T, Allocator)
|
||||||
value.SetString("Banana", 6);
|
{
|
||||||
x.AddMember(name, value, allocator);
|
Value o(kObjectType);
|
||||||
|
o.AddMember("true", true, allocator);
|
||||||
|
o.AddMember("false", false, allocator);
|
||||||
|
o.AddMember("int", -1, allocator);
|
||||||
|
o.AddMember("uint", 1u, allocator);
|
||||||
|
o.AddMember("int64", INT64_C(-4294967296), allocator);
|
||||||
|
o.AddMember("uint64", UINT64_C(4294967296), allocator);
|
||||||
|
o.AddMember("double", 3.14, allocator);
|
||||||
|
o.AddMember("string", "Jelly", allocator);
|
||||||
|
|
||||||
|
EXPECT_TRUE(o["true"].GetBool());
|
||||||
|
EXPECT_FALSE(o["false"].GetBool());
|
||||||
|
EXPECT_EQ(-1, o["int"].GetInt());
|
||||||
|
EXPECT_EQ(1u, o["uint"].GetUint());
|
||||||
|
EXPECT_EQ(INT64_C(-4294967296), o["int64"].GetInt64());
|
||||||
|
EXPECT_EQ(UINT64_C(4294967296), o["uint64"].GetUint64());
|
||||||
|
EXPECT_STREQ("Jelly",o["string"].GetString());
|
||||||
|
}
|
||||||
|
|
||||||
// Tests a member with null character
|
// Tests a member with null character
|
||||||
|
Value name;
|
||||||
const Value C0D("C\0D", 3);
|
const Value C0D("C\0D", 3);
|
||||||
name.SetString(C0D.GetString(), 3);
|
name.SetString(C0D.GetString(), 3);
|
||||||
value.SetString("CherryD", 7);
|
value.SetString("CherryD", 7);
|
||||||
@ -523,7 +625,7 @@ TEST(Value, Object) {
|
|||||||
EXPECT_TRUE(y.HasMember("A"));
|
EXPECT_TRUE(y.HasMember("A"));
|
||||||
EXPECT_TRUE(y.HasMember("B"));
|
EXPECT_TRUE(y.HasMember("B"));
|
||||||
|
|
||||||
name.SetString("C\0D", 3);
|
name.SetString("C\0D");
|
||||||
EXPECT_TRUE(x.HasMember(name));
|
EXPECT_TRUE(x.HasMember(name));
|
||||||
EXPECT_TRUE(y.HasMember(name));
|
EXPECT_TRUE(y.HasMember(name));
|
||||||
|
|
||||||
@ -617,6 +719,7 @@ TEST(Value, BigNestedObject) {
|
|||||||
char name1[10];
|
char name1[10];
|
||||||
sprintf(name1, "%d", i);
|
sprintf(name1, "%d", i);
|
||||||
|
|
||||||
|
// Value name(name1); // should not compile
|
||||||
Value name(name1, (SizeType)strlen(name1), allocator);
|
Value name(name1, (SizeType)strlen(name1), allocator);
|
||||||
Value object(kObjectType);
|
Value object(kObjectType);
|
||||||
|
|
||||||
@ -629,6 +732,7 @@ TEST(Value, BigNestedObject) {
|
|||||||
object.AddMember(name, number, allocator);
|
object.AddMember(name, number, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// x.AddMember(name1, object, allocator); // should not compile
|
||||||
x.AddMember(name, object, allocator);
|
x.AddMember(name, object, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user