Commit 4007301e authored by Philipp A. Hartmann's avatar Philipp A. Hartmann

Add a wrapper for constant string references

parent 3bfffa3c
...@@ -174,6 +174,51 @@ struct GenericMemberIterator<true,Encoding,Allocator> { ...@@ -174,6 +174,51 @@ struct GenericMemberIterator<true,Encoding,Allocator> {
#endif // RAPIDJSON_NOMEMBERITERATORCLASS #endif // RAPIDJSON_NOMEMBERITERATORCLASS
///////////////////////////////////////////////////////////////////////////////
// GenericStringRef
//! Reference to a constant string (not taking a copy)
template<typename CharType>
struct GenericStringRef {
typedef CharType Ch; //!< character type of the string
//! Create string reference from \c const character array
template<SizeType N>
GenericStringRef(const CharType (&str)[N])
: s(str), length(N-1) {}
//! Explicitly create string reference from \c const character pointer
explicit GenericStringRef(const CharType* str)
: s(str), length(internal::StrLen(str)){}
//! Create constant string reference from pointer and length
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* s; //!< plain CharType pointer
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
private:
//! Disallow construction from non-const array
template<SizeType N>
GenericStringRef(CharType (&str)[N]) /* = delete */;
};
//! Mark a character pointer as constant string
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str) {
return GenericStringRef<CharType>(str, internal::StrLen(str));
}
//! Mark a character pointer as constant string
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
return GenericStringRef<CharType>(str, SizeType(length));
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericValue // GenericValue
...@@ -196,6 +241,7 @@ public: ...@@ -196,6 +241,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,9 +253,11 @@ public: ...@@ -207,9 +253,11 @@ 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);
//! Disabled constructor for arbitrary pointers.
template<typename T> explicit GenericValue(T*);
public: public:
...@@ -283,16 +331,16 @@ public: ...@@ -283,16 +331,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 +387,17 @@ public: ...@@ -339,12 +387,17 @@ public:
return *this; return *this;
} }
//! Assignment of constant string reference (no copy)
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.
*/ */
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;
...@@ -428,7 +481,7 @@ public: ...@@ -428,7 +481,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 +534,7 @@ public: ...@@ -481,7 +534,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);
} }
...@@ -530,19 +583,23 @@ public: ...@@ -530,19 +583,23 @@ 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); 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)); GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
return AddMember(n, value, allocator); GenericValue v(value);
return AddMember(name, v, allocator);
} }
//! Add any primitive value as member (name-value pair) to the object.
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 +610,7 @@ public: ...@@ -553,7 +610,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);
} }
...@@ -657,7 +714,7 @@ int z = a[0u].GetInt(); // This works too. ...@@ -657,7 +714,7 @@ 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 The value to be appended.
\param allocator The allocator for allocating memory. It must be the same one use previously. \param allocator The allocator for allocating memory. It must be the same one use previously.
\return The value itself for fluent API. \return The value itself for fluent API.
...@@ -672,8 +729,15 @@ int z = a[0u].GetInt(); // This works too. ...@@ -672,8 +729,15 @@ int z = a[0u].GetInt(); // This works too.
return *this; return *this;
} }
//! Append a constant string reference at the end of the array.
GenericValue& PushBack(StringRefType value, Allocator& allocator) {
return (*this).template PushBack<StringRefType>(value, allocator);
}
//! Append a primitive value at the end of the array.
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);
} }
...@@ -728,13 +792,13 @@ int z = a[0u].GetInt(); // This works too. ...@@ -728,13 +792,13 @@ int z = a[0u].GetInt(); // This works too.
\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.
*/ */
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.
*/ */
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.
...@@ -743,14 +807,14 @@ int z = a[0u].GetInt(); // This works too. ...@@ -743,14 +807,14 @@ int z = a[0u].GetInt(); // This works too.
\param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator(). \param allocator Allocator for allocating copied buffer. Commonly use document.GetAllocator().
\return The value itself for fluent API. \return The value itself for fluent API.
*/ */
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 document.GetAllocator().
\return The value itself for fluent API. \return The value itself for fluent API.
*/ */
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 +970,19 @@ private: ...@@ -906,21 +970,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
......
...@@ -30,6 +30,9 @@ template <typename T> struct IsSame<T,T> : TrueType {}; ...@@ -30,6 +30,9 @@ template <typename T> struct IsSame<T,T> : TrueType {};
template <typename T> struct IsConst : FalseType {}; template <typename T> struct IsConst : FalseType {};
template <typename T> struct IsConst<const T> : TrueType {}; 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 {
enum { Value = enum { Value =
...@@ -64,6 +67,9 @@ template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment