From dd901f498b858ada40aaea8fc158d5d067701ae8 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sat, 4 Jul 2015 01:57:24 +0200 Subject: [PATCH 1/4] add GenericDocument<>::Swap See #368. --- include/rapidjson/document.h | 16 ++++++++++++++++ include/rapidjson/internal/stack.h | 13 +++++++++++++ test/unittest/documenttest.cpp | 14 +++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 889cdfaed..5eeef9c9e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1803,6 +1803,22 @@ class GenericDocument : public GenericValue { } #endif + //! Exchange the contents of this document with those of another. + /*! + \param other Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { + using std::swap; + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + swap(allocator_, rhs.allocator_); + swap(ownAllocator_, rhs.ownAllocator_); + swap(parseResult_, rhs.parseResult_); + return *this; + } + //!@name Parse from stream //!@{ diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index bb31cc0d3..198c866d8 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -15,6 +15,8 @@ #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ +#include // std::swap + #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN @@ -81,6 +83,17 @@ class Stack { } #endif + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { + using std::swap; + + swap(allocator_, rhs.allocator_); + swap(ownAllocator_, rhs.ownAllocator_); + swap(stack_, rhs.stack_); + swap(stackTop_, rhs.stackTop_); + swap(stackEnd_, rhs.stackEnd_); + swap(initialCapacity_, rhs.initialCapacity_); + } + void Clear() { stackTop_ = stack_; } void ShrinkToFit() { diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 2ee6b1039..3db7cd8de 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -202,7 +202,8 @@ TEST(Document, Swap) { o.SetObject().AddMember("a", 1, a); // Swap between Document and Value - d1.Swap(o); + // d1.Swap(o); // doesn't compile + o.Swap(d1); EXPECT_TRUE(d1.IsObject()); EXPECT_TRUE(o.IsArray()); @@ -212,8 +213,19 @@ TEST(Document, Swap) { d1.Swap(d2); EXPECT_TRUE(d1.IsArray()); EXPECT_TRUE(d2.IsObject()); + EXPECT_EQ(&d2.GetAllocator(), &a); + + // reset value + Value().Swap(d1); + EXPECT_TRUE(d1.IsNull()); + + // reset document, including allocator + Document().Swap(d2); + EXPECT_TRUE(d2.IsNull()); + EXPECT_NE(&d2.GetAllocator(), &a); } + // This should be slow due to assignment in inner-loop. struct OutputStringStream : public std::ostringstream { typedef char Ch; From 0ebe16e1695fd9ed31f933a269d13a05d73eaf2e Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Fri, 10 Jul 2015 17:06:52 +0200 Subject: [PATCH 2/4] add and use simplified "internal::Swap" This avoids the dependency on the header, as suggested by @miloyip in #376. --- include/rapidjson/document.h | 7 +++--- include/rapidjson/internal/stack.h | 17 ++++++-------- include/rapidjson/internal/swap.h | 37 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 include/rapidjson/internal/swap.h diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 5eeef9c9e..3496c2b90 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1810,12 +1810,11 @@ class GenericDocument : public GenericValue { \see GenericValue::Swap */ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { - using std::swap; ValueType::Swap(rhs); stack_.Swap(rhs.stack_); - swap(allocator_, rhs.allocator_); - swap(ownAllocator_, rhs.ownAllocator_); - swap(parseResult_, rhs.parseResult_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); return *this; } diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 198c866d8..0d4a7f78f 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -15,9 +15,8 @@ #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ -#include // std::swap - #include "../rapidjson.h" +#include "swap.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -84,14 +83,12 @@ class Stack { #endif void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { - using std::swap; - - swap(allocator_, rhs.allocator_); - swap(ownAllocator_, rhs.ownAllocator_); - swap(stack_, rhs.stack_); - swap(stackTop_, rhs.stackTop_); - swap(stackEnd_, rhs.stackEnd_); - swap(initialCapacity_, rhs.initialCapacity_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); } void Clear() { stackTop_ = stack_; } diff --git a/include/rapidjson/internal/swap.h b/include/rapidjson/internal/swap.h new file mode 100644 index 000000000..41e7e2008 --- /dev/null +++ b/include/rapidjson/internal/swap.h @@ -0,0 +1,37 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +//! Custom swap() to avoid dependency on C++ header +/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. + \note This has the same semantics as std::swap(). +*/ +template +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { + T tmp = a; + a = b; + b = tmp; +} + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_SWAP_H_ From 46e1696316e2d33c0198af2138ab481d985439f0 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Mon, 13 Jul 2015 09:35:15 +0200 Subject: [PATCH 3/4] add free inline `swap` functions --- include/rapidjson/document.h | 4 ++++ test/unittest/documenttest.cpp | 12 ++++++++++++ test/unittest/valuetest.cpp | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 3496c2b90..007fa943b 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -660,6 +660,8 @@ class GenericValue { return *this; } + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + //! Prepare Value for move semantics /*! \return *this */ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } @@ -1818,6 +1820,8 @@ class GenericDocument : public GenericValue { return *this; } + friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + //!@name Parse from stream //!@{ diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 3db7cd8de..810a99c61 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -19,6 +19,7 @@ #include "rapidjson/encodedstream.h" #include "rapidjson/stringbuffer.h" #include +#include using namespace rapidjson; @@ -223,6 +224,17 @@ TEST(Document, Swap) { Document().Swap(d2); EXPECT_TRUE(d2.IsNull()); EXPECT_NE(&d2.GetAllocator(), &a); + + // testing std::swap compatibility + d1.SetBool(true); + using std::swap; + swap(d1, d2); + EXPECT_TRUE(d1.IsNull()); + EXPECT_TRUE(d2.IsTrue()); + + swap(o, d2); + EXPECT_TRUE(o.IsTrue()); + EXPECT_TRUE(d2.IsArray()); } diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index f14669a69..900783c08 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -272,6 +272,12 @@ TEST(Value, Swap) { EXPECT_TRUE(v1.IsObject()); EXPECT_TRUE(v2.IsInt()); EXPECT_EQ(1234, v2.GetInt()); + + // testing std::swap compatibility + using std::swap; + swap(v1, v2); + EXPECT_TRUE(v1.IsInt()); + EXPECT_TRUE(v2.IsObject()); } TEST(Value, Null) { From c2b586492724c7bbfa8bf176caee400b19f66681 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Mon, 13 Jul 2015 14:38:24 +0200 Subject: [PATCH 4/4] add documentation for 'swap' friend functions --- include/rapidjson/document.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 007fa943b..ae7e829f3 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -660,6 +660,18 @@ class GenericValue { return *this; } + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Prepare Value for move semantics @@ -1820,6 +1832,18 @@ class GenericDocument : public GenericValue { return *this; } + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //!@name Parse from stream