Commit 9b6af555 authored by Milo Yip's avatar Milo Yip

Merge branch 'master' into issue728_threadsafe

parents 769185d6 23632279
...@@ -128,7 +128,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str); ...@@ -128,7 +128,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
## 解析错误 {#ParseError} ## 解析错误 {#ParseError}
当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会 * 维持不便 *。可使用 `bool HasParseError()``ParseErrorCode GetParseError()``size_t GetParseOffset()` 获取解析的错误状态。 当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()``ParseErrorCode GetParseError()``size_t GetParseOffset()` 获取解析的错误状态。
解析错误代号 | 描述 解析错误代号 | 描述
--------------------------------------------|--------------------------------------------------- --------------------------------------------|---------------------------------------------------
......
...@@ -163,9 +163,9 @@ ...@@ -163,9 +163,9 @@
## Document/Value (DOM) ## Document/Value (DOM)
1. 什么是转移语?为什么? 1. 什么是转移语?为什么?
`Value` 不用复制语意,而使用了转移语意。这是指,当把来源值赋值于目标值时,来源值的所有权会转移至目标值。 `Value` 不用复制语义,而使用了转移语义。这是指,当把来源值赋值于目标值时,来源值的所有权会转移至目标值。
由于转移快于复制,此设计决定强迫使用者注意到复制的消耗。 由于转移快于复制,此设计决定强迫使用者注意到复制的消耗。
......
...@@ -157,7 +157,7 @@ As `SchemaDocument` does not know how to resolve such URI, it needs a user-provi ...@@ -157,7 +157,7 @@ As `SchemaDocument` does not know how to resolve such URI, it needs a user-provi
~~~ ~~~
class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider { class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public: public:
virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) { virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
// Resolve the uri and returns a pointer to that schema. // Resolve the uri and returns a pointer to that schema.
} }
}; };
...@@ -185,7 +185,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d ...@@ -185,7 +185,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
|Syntax|Description| |Syntax|Description|
|------|-----------| |------|-----------|
|`ab` | Concatenation | |`ab` | Concatenation |
|`a|b` | Alternation | |<code>a&#124;b</code> | Alternation |
|`a?` | Zero or one | |`a?` | Zero or one |
|`a*` | Zero or more | |`a*` | Zero or more |
|`a+` | One or more | |`a+` | One or more |
...@@ -202,7 +202,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d ...@@ -202,7 +202,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
|`[^abc]` | Negated character classes | |`[^abc]` | Negated character classes |
|`[^a-c]` | Negated character class range | |`[^a-c]` | Negated character class range |
|`[\b]` | Backspace (U+0008) | |`[\b]` | Backspace (U+0008) |
|`\|`, `\\`, ... | Escape characters | |<code>\\&#124;</code>, `\\`, ... | Escape characters |
|`\f` | Form feed (U+000C) | |`\f` | Form feed (U+000C) |
|`\n` | Line feed (U+000A) | |`\n` | Line feed (U+000A) |
|`\r` | Carriage return (U+000D) | |`\r` | Carriage return (U+000D) |
......
...@@ -157,7 +157,7 @@ JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understand ...@@ -157,7 +157,7 @@ JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understand
~~~ ~~~
class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider { class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public: public:
virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) { virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
// Resolve the uri and returns a pointer to that schema. // Resolve the uri and returns a pointer to that schema.
} }
}; };
...@@ -185,7 +185,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 ...@@ -185,7 +185,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用
|语法|描述| |语法|描述|
|------|-----------| |------|-----------|
|`ab` | 串联 | |`ab` | 串联 |
|`a|b` | 交替 | |<code>a&#124;b</code> | 交替 |
|`a?` | 零或一次 | |`a?` | 零或一次 |
|`a*` | 零或多次 | |`a*` | 零或多次 |
|`a+` | 一或多次 | |`a+` | 一或多次 |
...@@ -202,7 +202,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 ...@@ -202,7 +202,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用
|`[^abc]` | 字符组取反 | |`[^abc]` | 字符组取反 |
|`[^a-c]` | 字符组范围取反 | |`[^a-c]` | 字符组范围取反 |
|`[\b]` | 退格符 (U+0008) | |`[\b]` | 退格符 (U+0008) |
|`\|`, `\\`, ... | 转义字符 | |<code>\\&#124;</code>, `\\`, ... | 转义字符 |
|`\f` | 馈页 (U+000C) | |`\f` | 馈页 (U+000C) |
|`\n` | 馈行 (U+000A) | |`\n` | 馈行 (U+000A) |
|`\r` | 回车 (U+000D) | |`\r` | 回车 (U+000D) |
......
...@@ -292,7 +292,7 @@ Value o(kObjectType); ...@@ -292,7 +292,7 @@ Value o(kObjectType);
Value a(kArrayType); Value a(kArrayType);
~~~~~~~~~~ ~~~~~~~~~~
## 转移语(Move Semantics) {#MoveSemantics} ## 转移语(Move Semantics) {#MoveSemantics}
在设计 RapidJSON 时有一个非常特别的决定,就是 Value 赋值并不是把来源 Value 复制至目的 Value,而是把把来源 Value 转移(move)至目的 Value。例如: 在设计 RapidJSON 时有一个非常特别的决定,就是 Value 赋值并不是把来源 Value 复制至目的 Value,而是把把来源 Value 转移(move)至目的 Value。例如:
...@@ -302,13 +302,13 @@ Value b(456); ...@@ -302,13 +302,13 @@ Value b(456);
b = a; // a 变成 Null,b 变成数字 123。 b = a; // a 变成 Null,b 变成数字 123。
~~~~~~~~~~ ~~~~~~~~~~
![使用移动语赋值。](diagram/move1.png) ![使用移动语赋值。](diagram/move1.png)
为什么?此语有何优点? 为什么?此语有何优点?
最简单的答案就是性能。对于固定大小的 JSON 类型(Number、True、False、Null),复制它们是简单快捷。然而,对于可变大小的 JSON 类型(String、Array、Object),复制它们会产生大量开销,而且这些开销常常不被察觉。尤其是当我们需要创建临时 Object,把它复制至另一变量,然后再析构它。 最简单的答案就是性能。对于固定大小的 JSON 类型(Number、True、False、Null),复制它们是简单快捷。然而,对于可变大小的 JSON 类型(String、Array、Object),复制它们会产生大量开销,而且这些开销常常不被察觉。尤其是当我们需要创建临时 Object,把它复制至另一变量,然后再析构它。
例如,若使用正常 * 复制 * 例如,若使用正常 * 复制 *
~~~~~~~~~~cpp ~~~~~~~~~~cpp
Value o(kObjectType); Value o(kObjectType);
...@@ -321,15 +321,15 @@ Value o(kObjectType); ...@@ -321,15 +321,15 @@ Value o(kObjectType);
} }
~~~~~~~~~~ ~~~~~~~~~~
![复制语产生大量的复制操作。](diagram/move2.png) ![复制语产生大量的复制操作。](diagram/move2.png)
那个 `o` Object 需要分配一个和 contacts 相同大小的缓冲区,对 conacts 做深度复制,并最终要析构 contacts。这样会产生大量无必要的内存分配/释放,以及内存复制。 那个 `o` Object 需要分配一个和 contacts 相同大小的缓冲区,对 conacts 做深度复制,并最终要析构 contacts。这样会产生大量无必要的内存分配/释放,以及内存复制。
有一些方案可避免实质地复制这些数据,例如引用计数(reference counting)、垃圾回收(garbage collection, GC)。 有一些方案可避免实质地复制这些数据,例如引用计数(reference counting)、垃圾回收(garbage collection, GC)。
为了使 RapidJSON 简单及快速,我们选择了对赋值采用 * 转移 *。这方法与 `std::auto_ptr` 相似,都是在赋值时转移拥有权。转移快得多简单得多,只需要析构原来的 Value,把来源 `memcpy()` 至目标,最后把来源设置为 Null 类型。 为了使 RapidJSON 简单及快速,我们选择了对赋值采用 * 转移 *。这方法与 `std::auto_ptr` 相似,都是在赋值时转移拥有权。转移快得多简单得多,只需要析构原来的 Value,把来源 `memcpy()` 至目标,最后把来源设置为 Null 类型。
因此,使用转移语后,上面的例子变成: 因此,使用转移语后,上面的例子变成:
~~~~~~~~~~cpp ~~~~~~~~~~cpp
Value o(kObjectType); Value o(kObjectType);
...@@ -341,11 +341,11 @@ Value o(kObjectType); ...@@ -341,11 +341,11 @@ Value o(kObjectType);
} }
~~~~~~~~~~ ~~~~~~~~~~
![转移语不需复制。](diagram/move3.png) ![转移语不需复制。](diagram/move3.png)
在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语意,其它修改形函数如 `AddMember()`, `PushBack()` 也采用转移语意 在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语义,其它修改形函数如 `AddMember()`, `PushBack()` 也采用转移语义
### 转移语及临时值 {#TemporaryValues} ### 转移语及临时值 {#TemporaryValues}
有时候,我们想直接构造一个 Value 并传递给一个“转移”函数(如 `PushBack()``AddMember()`)。由于临时对象是不能转换为正常的 Value 引用,我们加入了一个方便的 `Move()` 函数: 有时候,我们想直接构造一个 Value 并传递给一个“转移”函数(如 `PushBack()``AddMember()`)。由于临时对象是不能转换为正常的 Value 引用,我们加入了一个方便的 `Move()` 函数:
......
...@@ -672,6 +672,9 @@ public: ...@@ -672,6 +672,9 @@ public:
//! Constructor for double value. //! Constructor for double value.
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
//! Constructor for float value.
explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; }
//! 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) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
...@@ -1671,7 +1674,7 @@ public: ...@@ -1671,7 +1674,7 @@ public:
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; }
//@} //@}
......
...@@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH ...@@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#if defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Combination of PrettyWriter format flags. //! Combination of PrettyWriter format flags.
...@@ -57,6 +62,11 @@ public: ...@@ -57,6 +62,11 @@ public:
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
PrettyWriter(PrettyWriter&& rhs) :
Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
#endif
//! Set custom indentation. //! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
\param indentCharCount Number of indent characters for each indentation level. \param indentCharCount Number of indent characters for each indentation level.
...@@ -254,6 +264,10 @@ private: ...@@ -254,6 +264,10 @@ private:
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
......
...@@ -575,7 +575,7 @@ private: ...@@ -575,7 +575,7 @@ private:
} }
} }
else if (RAPIDJSON_LIKELY(Consume(is, '/'))) else if (RAPIDJSON_LIKELY(Consume(is, '/')))
while (is.Peek() != '\0' && is.Take() != '\n'); while (is.Peek() != '\0' && is.Take() != '\n') {}
else else
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
......
...@@ -78,8 +78,12 @@ public: ...@@ -78,8 +78,12 @@ public:
return stack_.template Bottom<Ch>(); return stack_.template Bottom<Ch>();
} }
//! Get the size of string in bytes in the string buffer.
size_t GetSize() const { return stack_.GetSize(); } size_t GetSize() const { return stack_.GetSize(); }
//! Get the length of string in Ch in the string buffer.
size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
static const size_t kDefaultCapacity = 256; static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_; mutable internal::Stack<Allocator> stack_;
......
...@@ -42,6 +42,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant ...@@ -42,6 +42,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
...@@ -103,6 +104,13 @@ public: ...@@ -103,6 +104,13 @@ public:
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Writer(Writer&& rhs) :
os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
rhs.os_ = 0;
}
#endif
//! Reset the writer with a new stream. //! Reset the writer with a new stream.
/*! /*!
This function reset the writer with a new stream and default settings, This function reset the writer with a new stream and default settings,
......
...@@ -18,6 +18,11 @@ ...@@ -18,6 +18,11 @@
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
#include "rapidjson/filewritestream.h" #include "rapidjson/filewritestream.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif
using namespace rapidjson; using namespace rapidjson;
static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}"; static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}";
...@@ -201,3 +206,30 @@ TEST(PrettyWriter, RawValue) { ...@@ -201,3 +206,30 @@ TEST(PrettyWriter, RawValue) {
"}", "}",
buffer.GetString()); buffer.GetString());
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
static PrettyWriter<StringBuffer> WriterGen(StringBuffer &target) {
PrettyWriter<StringBuffer> writer(target);
writer.StartObject();
writer.Key("a");
writer.Int(1);
return writer;
}
TEST(PrettyWriter, MoveCtor) {
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(WriterGen(buffer));
writer.EndObject();
EXPECT_TRUE(writer.IsComplete());
EXPECT_STREQ(
"{\n"
" \"a\": 1\n"
"}",
buffer.GetString());
}
#endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
...@@ -26,6 +26,7 @@ using namespace rapidjson; ...@@ -26,6 +26,7 @@ using namespace rapidjson;
TEST(StringBuffer, InitialSize) { TEST(StringBuffer, InitialSize) {
StringBuffer buffer; StringBuffer buffer;
EXPECT_EQ(0u, buffer.GetSize()); EXPECT_EQ(0u, buffer.GetSize());
EXPECT_EQ(0u, buffer.GetLength());
EXPECT_STREQ("", buffer.GetString()); EXPECT_STREQ("", buffer.GetString());
} }
...@@ -34,14 +35,17 @@ TEST(StringBuffer, Put) { ...@@ -34,14 +35,17 @@ TEST(StringBuffer, Put) {
buffer.Put('A'); buffer.Put('A');
EXPECT_EQ(1u, buffer.GetSize()); EXPECT_EQ(1u, buffer.GetSize());
EXPECT_EQ(1u, buffer.GetLength());
EXPECT_STREQ("A", buffer.GetString()); EXPECT_STREQ("A", buffer.GetString());
} }
TEST(StringBuffer, PutN_Issue672) { TEST(StringBuffer, PutN_Issue672) {
GenericStringBuffer<UTF8<>, MemoryPoolAllocator<> > buffer; GenericStringBuffer<UTF8<>, MemoryPoolAllocator<> > buffer;
EXPECT_EQ(0, buffer.GetSize()); EXPECT_EQ(0, buffer.GetSize());
EXPECT_EQ(0, buffer.GetLength());
rapidjson::PutN(buffer, ' ', 1); rapidjson::PutN(buffer, ' ', 1);
EXPECT_EQ(1, buffer.GetSize()); EXPECT_EQ(1, buffer.GetSize());
EXPECT_EQ(1, buffer.GetLength());
} }
TEST(StringBuffer, Clear) { TEST(StringBuffer, Clear) {
...@@ -52,6 +56,7 @@ TEST(StringBuffer, Clear) { ...@@ -52,6 +56,7 @@ TEST(StringBuffer, Clear) {
buffer.Clear(); buffer.Clear();
EXPECT_EQ(0u, buffer.GetSize()); EXPECT_EQ(0u, buffer.GetSize());
EXPECT_EQ(0u, buffer.GetLength());
EXPECT_STREQ("", buffer.GetString()); EXPECT_STREQ("", buffer.GetString());
} }
...@@ -60,6 +65,7 @@ TEST(StringBuffer, Push) { ...@@ -60,6 +65,7 @@ TEST(StringBuffer, Push) {
buffer.Push(5); buffer.Push(5);
EXPECT_EQ(5u, buffer.GetSize()); EXPECT_EQ(5u, buffer.GetSize());
EXPECT_EQ(5u, buffer.GetLength());
// Causes sudden expansion to make the stack's capacity equal to size // Causes sudden expansion to make the stack's capacity equal to size
buffer.Push(65536u); buffer.Push(65536u);
...@@ -76,9 +82,19 @@ TEST(StringBuffer, Pop) { ...@@ -76,9 +82,19 @@ TEST(StringBuffer, Pop) {
buffer.Pop(3); buffer.Pop(3);
EXPECT_EQ(2u, buffer.GetSize()); EXPECT_EQ(2u, buffer.GetSize());
EXPECT_EQ(2u, buffer.GetLength());
EXPECT_STREQ("AB", buffer.GetString()); EXPECT_STREQ("AB", buffer.GetString());
} }
TEST(StringBuffer, GetLength_Issue744) {
GenericStringBuffer<UTF16<wchar_t> > buffer;
buffer.Put('A');
buffer.Put('B');
buffer.Put('C');
EXPECT_EQ(3u * sizeof(wchar_t), buffer.GetSize());
EXPECT_EQ(3u, buffer.GetLength());
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if 0 // Many old compiler does not support these. Turn it off temporaily. #if 0 // Many old compiler does not support these. Turn it off temporaily.
...@@ -130,18 +146,23 @@ TEST(StringBuffer, MoveConstructor) { ...@@ -130,18 +146,23 @@ TEST(StringBuffer, MoveConstructor) {
x.Put('D'); x.Put('D');
EXPECT_EQ(4u, x.GetSize()); EXPECT_EQ(4u, x.GetSize());
EXPECT_EQ(4u, x.GetLength());
EXPECT_STREQ("ABCD", x.GetString()); EXPECT_STREQ("ABCD", x.GetString());
// StringBuffer y(x); // does not compile (!is_copy_constructible) // StringBuffer y(x); // does not compile (!is_copy_constructible)
StringBuffer y(std::move(x)); StringBuffer y(std::move(x));
EXPECT_EQ(0u, x.GetSize()); EXPECT_EQ(0u, x.GetSize());
EXPECT_EQ(0u, x.GetLength());
EXPECT_EQ(4u, y.GetSize()); EXPECT_EQ(4u, y.GetSize());
EXPECT_EQ(4u, y.GetLength());
EXPECT_STREQ("ABCD", y.GetString()); EXPECT_STREQ("ABCD", y.GetString());
// StringBuffer z = y; // does not compile (!is_copy_assignable) // StringBuffer z = y; // does not compile (!is_copy_assignable)
StringBuffer z = std::move(y); StringBuffer z = std::move(y);
EXPECT_EQ(0u, y.GetSize()); EXPECT_EQ(0u, y.GetSize());
EXPECT_EQ(0u, y.GetLength());
EXPECT_EQ(4u, z.GetSize()); EXPECT_EQ(4u, z.GetSize());
EXPECT_EQ(4u, z.GetLength());
EXPECT_STREQ("ABCD", z.GetString()); EXPECT_STREQ("ABCD", z.GetString());
} }
...@@ -153,13 +174,14 @@ TEST(StringBuffer, MoveAssignment) { ...@@ -153,13 +174,14 @@ TEST(StringBuffer, MoveAssignment) {
x.Put('D'); x.Put('D');
EXPECT_EQ(4u, x.GetSize()); EXPECT_EQ(4u, x.GetSize());
EXPECT_EQ(4u, x.GetLength());
EXPECT_STREQ("ABCD", x.GetString()); EXPECT_STREQ("ABCD", x.GetString());
StringBuffer y; StringBuffer y;
// y = x; // does not compile (!is_copy_assignable) // y = x; // does not compile (!is_copy_assignable)
y = std::move(x); y = std::move(x);
EXPECT_EQ(0u, x.GetSize()); EXPECT_EQ(0u, x.GetSize());
EXPECT_EQ(4u, y.GetSize()); EXPECT_EQ(4u, y.GetLength());
EXPECT_STREQ("ABCD", y.GetString()); EXPECT_STREQ("ABCD", y.GetString());
} }
......
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
#include "rapidjson/memorybuffer.h" #include "rapidjson/memorybuffer.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif
using namespace rapidjson; using namespace rapidjson;
TEST(Writer, Compact) { TEST(Writer, Compact) {
...@@ -495,3 +500,25 @@ TEST(Writer, RawValue) { ...@@ -495,3 +500,25 @@ TEST(Writer, RawValue) {
EXPECT_TRUE(writer.IsComplete()); EXPECT_TRUE(writer.IsComplete());
EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString()); EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString());
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
static Writer<StringBuffer> WriterGen(StringBuffer &target) {
Writer<StringBuffer> writer(target);
writer.StartObject();
writer.Key("a");
writer.Int(1);
return writer;
}
TEST(Writer, MoveCtor) {
StringBuffer buffer;
Writer<StringBuffer> writer(WriterGen(buffer));
writer.EndObject();
EXPECT_TRUE(writer.IsComplete());
EXPECT_STREQ("{\"a\":1}", buffer.GetString());
}
#endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
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