-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Initial C++11 move support #128
Changes from 10 commits
1beec85
defc3aa
5f6967b
a16fe36
5656078
c1c9ba7
a9d2b75
b5f9d60
36031b1
5672d24
56625bd
8ae2266
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
/*! \file document.h */ | ||
|
||
#include "reader.h" | ||
#include "internal/meta.h" | ||
#include "internal/strfunc.h" | ||
#include <new> // placement new | ||
|
||
|
@@ -38,15 +39,17 @@ RAPIDJSON_DIAG_OFF(effc++) | |
/////////////////////////////////////////////////////////////////////////////// | ||
// RAPIDJSON_HAS_STDSTRING | ||
|
||
#ifndef RAPIDJSON_HAS_STDSTRING | ||
#ifdef RAPIDJSON_DOXYGEN_RUNNING | ||
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation | ||
#else | ||
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default | ||
#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 | ||
By defining this preprocessor symbol to \c 1, several convenience functions for using | ||
\ref rapidjson::GenericValue with \c std::string are enabled, especially | ||
for construction and comparison. | ||
|
||
|
@@ -56,7 +59,6 @@ RAPIDJSON_DIAG_OFF(effc++) | |
#endif // RAPIDJSON_HAS_STDSTRING | ||
|
||
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS | ||
#include "internal/meta.h" | ||
#include <iterator> // std::iterator, std::random_access_iterator_tag | ||
#endif | ||
|
||
|
@@ -363,7 +365,7 @@ inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) | |
return GenericStringRef<CharType>(str, SizeType(length)); | ||
} | ||
|
||
#ifdef RAPIDJSON_HAS_STDSTRING | ||
#if 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 | ||
|
@@ -414,7 +416,14 @@ class GenericValue { | |
//@{ | ||
|
||
//! Default constructor creates a null value. | ||
GenericValue() : data_(), flags_(kNullFlag) {} | ||
GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {} | ||
|
||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||
//! Move constructor in C++11 | ||
GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) { | ||
rhs.flags_ = kNullFlag; // give up contents | ||
} | ||
#endif | ||
|
||
private: | ||
//! Copy constructor is not permitted. | ||
|
@@ -427,7 +436,7 @@ class GenericValue { | |
\param type Type of the value. | ||
\note Default content for number is zero. | ||
*/ | ||
GenericValue(Type type) : data_(), flags_() { | ||
GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { | ||
static const unsigned defaultFlags[7] = { | ||
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag, | ||
kNumberAnyFlag | ||
|
@@ -454,31 +463,31 @@ class GenericValue { | |
*/ | ||
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen | ||
template <typename T> | ||
explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) | ||
explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT | ||
#else | ||
explicit GenericValue(bool b) | ||
explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT | ||
#endif | ||
: data_(), flags_(b ? kTrueFlag : kFalseFlag) { | ||
// safe-guard against failing SFINAE | ||
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value)); | ||
} | ||
|
||
//! Constructor for int value. | ||
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) { | ||
explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) { | ||
data_.n.i64 = i; | ||
if (i >= 0) | ||
flags_ |= kUintFlag | kUint64Flag; | ||
} | ||
|
||
//! Constructor for unsigned value. | ||
explicit GenericValue(unsigned u) : data_(), flags_(kNumberUintFlag) { | ||
explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) { | ||
data_.n.u64 = u; | ||
if (!(u & 0x80000000)) | ||
flags_ |= kIntFlag | kInt64Flag; | ||
} | ||
|
||
//! Constructor for int64_t value. | ||
explicit GenericValue(int64_t i64) : data_(), flags_(kNumberInt64Flag) { | ||
explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) { | ||
data_.n.i64 = i64; | ||
if (i64 >= 0) { | ||
flags_ |= kNumberUint64Flag; | ||
|
@@ -492,7 +501,7 @@ class GenericValue { | |
} | ||
|
||
//! Constructor for uint64_t value. | ||
explicit GenericValue(uint64_t u64) : data_(), flags_(kNumberUint64Flag) { | ||
explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) { | ||
data_.n.u64 = u64; | ||
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) | ||
flags_ |= kInt64Flag; | ||
|
@@ -503,21 +512,21 @@ class GenericValue { | |
} | ||
|
||
//! Constructor for double value. | ||
explicit GenericValue(double d) : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } | ||
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } | ||
|
||
//! Constructor for constant string (i.e. do not make a copy of string) | ||
GenericValue(const Ch* s, SizeType length) : data_(), flags_() { SetStringRaw(StringRef(s, length)); } | ||
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); } | ||
|
||
//! Constructor for constant string (i.e. do not make a copy of string) | ||
explicit GenericValue(StringRefType s) : data_(), flags_() { SetStringRaw(s); } | ||
explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. |
||
|
||
//! Constructor for copy-string (i.e. do make a copy of string) | ||
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) | ||
GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } | ||
|
||
#ifdef RAPIDJSON_HAS_STDSTRING | ||
#if 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. | ||
*/ | ||
|
@@ -560,19 +569,26 @@ class GenericValue { | |
//! Assignment with move semantics. | ||
/*! \param rhs Source of the assignment. It will become a null value after assignment. | ||
*/ | ||
GenericValue& operator=(GenericValue& rhs) { | ||
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, even lvalue assignment is always a move in RapidJSON, see Move Semantics. |
||
RAPIDJSON_ASSERT(this != &rhs); | ||
this->~GenericValue(); | ||
RawAssign(rhs); | ||
return *this; | ||
} | ||
|
||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||
//! Move assignment in C++11 | ||
GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { | ||
return *this = rhs.Move(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Move() should also be marked as noexcept There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
} | ||
#endif | ||
|
||
//! 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) { | ||
GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { | ||
GenericValue s(str); | ||
return *this = s; | ||
} | ||
|
@@ -615,7 +631,7 @@ class GenericValue { | |
\param other Another value. | ||
\note Constant complexity. | ||
*/ | ||
GenericValue& Swap(GenericValue& other) { | ||
GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { | ||
GenericValue temp; | ||
temp.RawAssign(*this); | ||
RawAssign(other); | ||
|
@@ -675,7 +691,7 @@ 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 | ||
#if RAPIDJSON_HAS_STDSTRING | ||
//! Equal-to operator with string object | ||
/*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. | ||
*/ | ||
|
@@ -895,6 +911,23 @@ class GenericValue { | |
return *this; | ||
} | ||
|
||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||
GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { | ||
return AddMember(name, value, allocator); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Infinite recursion? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, inside the function, the rvalue-refs are lvalues again. This will call the |
||
} | ||
GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { | ||
return AddMember(name, value, allocator); | ||
} | ||
GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { | ||
return AddMember(name, value, allocator); | ||
} | ||
GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { | ||
GenericValue n(name); | ||
return AddMember(n, value, allocator); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. std::move(n) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? Even the lvalue-overload will move There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I need to get my head around the "non-standard" behavior of the value class... Sorry for that. BTW, with respect to the factor of 2 in line 904 (my iPad doesnt allow to leave a comment there?) have a llok here: https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No worries, thanks for the review. :-) Wrt the growth factor (also applies to the "object capacity", see o.capacity += (o.capacity >> 1); // * 1.5 and Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity + (data_.a.capacity >> 1), allocator); |
||
} | ||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||
|
||
|
||
//! Add a member (name-value pair) to the object. | ||
/*! \param name A constant string reference as name of member. | ||
\param value Value of any type. | ||
|
@@ -1135,6 +1168,12 @@ int z = a[0u].GetInt(); // This works too. | |
return *this; | ||
} | ||
|
||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||
GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { | ||
return PushBack(value, allocator); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Infinite recursion? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, see above. |
||
} | ||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | ||
|
||
//! 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(). | ||
|
@@ -1289,7 +1328,7 @@ int z = a[0u].GetInt(); // This works too. | |
*/ | ||
GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } | ||
|
||
#ifdef RAPIDJSON_HAS_STDSTRING | ||
#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(). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, this is not noexcept, since it will/can involve a memory allocation...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it won't allocate memory. See
SetStringRaw
(and comment before the constructor).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mixed that with the version taking the allocator (since I only used that for now)...