From 43b63b110075b01d70997ea0d36d2a0c81187441 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 7 Feb 2016 22:15:17 +0800 Subject: [PATCH 1/8] Add IStreamWrapper --- include/rapidjson/istreamwrapper.h | 98 +++++++++++++++ test/unittest/CMakeLists.txt | 1 + test/unittest/istreamwrappertest.cpp | 170 +++++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 include/rapidjson/istreamwrapper.h create mode 100644 test/unittest/istreamwrappertest.cpp diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h new file mode 100644 index 00000000..066fabd5 --- /dev/null +++ b/include/rapidjson/istreamwrapper.h @@ -0,0 +1,98 @@ +// 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. + +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class IStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + IStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} + + Ch Peek() const { + typename StreamType::int_type c = stream_.peek(); + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; + } + + Ch Take() { + typename StreamType::int_type c = stream_.get(); + if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { + count_++; + return static_cast(c); + } + else + return '\0'; + } + + // tellg() may return -1 when failed. So we count by ourself. + size_t Tell() const { return count_; } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. + int i; + bool hasError = false; + for (i = 0; i < 4; ++i) { + typename StreamType::int_type c = stream_.get(); + if (c == StreamType::traits_type::eof()) { + hasError = true; + stream_.clear(); + break; + } + peekBuffer_[i] = static_cast(c); + } + for (--i; i >= 0; --i) + stream_.putback(peekBuffer_[i]); + return !hasError ? peekBuffer_ : 0; + } + +private: + StreamType& stream_; + size_t count_; //!< Number of characters read. Note: + mutable Ch peekBuffer_[4]; +}; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index f82645fc..728ccf1a 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -7,6 +7,7 @@ set(UNITTEST_SOURCES fwdtest.cpp filestreamtest.cpp itoatest.cpp + istreamwrappertest.cpp jsoncheckertest.cpp namespacetest.cpp pointertest.cpp diff --git a/test/unittest/istreamwrappertest.cpp b/test/unittest/istreamwrappertest.cpp new file mode 100644 index 00000000..4b7c8035 --- /dev/null +++ b/test/unittest/istreamwrappertest.cpp @@ -0,0 +1,170 @@ +// 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. + +#include "unittest.h" + +#include "rapidjson/istreamwrapper.h" +#include "rapidjson/encodedstream.h" +#include "rapidjson/document.h" +#include +#include + +using namespace rapidjson; +using namespace std; + +template +static void TestStringStream() { + typedef typename StringStreamType::char_type Ch; + + { + StringStreamType iss; + IStreamWrapper is(iss); + EXPECT_EQ(0, is.Tell()); + if (sizeof(Ch) == 1) { + EXPECT_EQ(0, is.Peek4()); + EXPECT_EQ(0, is.Tell()); + } + EXPECT_EQ(0, is.Peek()); + EXPECT_EQ(0, is.Take()); + EXPECT_EQ(0, is.Tell()); + } + + { + Ch s[] = { 'A', 'B', 'C', '\0' }; + StringStreamType iss(s); + IStreamWrapper is(iss); + EXPECT_EQ(0, is.Tell()); + if (sizeof(Ch) == 1) + EXPECT_EQ(0, is.Peek4()); // less than 4 bytes + for (int i = 0; i < 3; i++) { + EXPECT_EQ(static_cast(i), is.Tell()); + EXPECT_EQ('A' + i, is.Peek()); + EXPECT_EQ('A' + i, is.Peek()); + EXPECT_EQ('A' + i, is.Take()); + } + EXPECT_EQ(3, is.Tell()); + EXPECT_EQ(0, is.Peek()); + EXPECT_EQ(0, is.Take()); + } + + { + Ch s[] = { 'A', 'B', 'C', 'D', 'E', '\0' }; + StringStreamType iss(s); + IStreamWrapper is(iss); + if (sizeof(Ch) == 1) { + const Ch* c = is.Peek4(); + for (int i = 0; i < 4; i++) + EXPECT_EQ('A' + i, c[i]); + EXPECT_EQ(0, is.Tell()); + } + for (int i = 0; i < 5; i++) { + EXPECT_EQ(static_cast(i), is.Tell()); + EXPECT_EQ('A' + i, is.Peek()); + EXPECT_EQ('A' + i, is.Peek()); + EXPECT_EQ('A' + i, is.Take()); + } + EXPECT_EQ(5, is.Tell()); + EXPECT_EQ(0, is.Peek()); + EXPECT_EQ(0, is.Take()); + } +} + +TEST(IStreamWrapper, istringstream) { + TestStringStream(); +} + +TEST(IStreamWrapper, stringstream) { + TestStringStream(); +} + +TEST(IStreamWrapper, wistringstream) { + TestStringStream(); +} + +TEST(IStreamWrapper, wstringstream) { + TestStringStream(); +} + +template +static bool Open(FileStreamType& fs, const char* filename) { + const char *paths[] = { + "encodings", + "bin/encodings", + "../bin/encodings", + "../../bin/encodings", + "../../../bin/encodings" + }; + char buffer[1024]; + for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + sprintf(buffer, "%s/%s", paths[i], filename); + fs.open(buffer, ios_base::in | ios_base::binary); + if (fs.is_open()) + return true; + } + return false; +} + +TEST(IStreamWrapper, ifstream) { + ifstream ifs; + ASSERT_TRUE(Open(ifs, "utf8bom.json")); + IStreamWrapper isw(ifs); + EncodedInputStream, IStreamWrapper > eis(isw); + Document d; + EXPECT_TRUE(!d.ParseStream(eis).HasParseError()); + EXPECT_TRUE(d.IsObject()); + EXPECT_EQ(5, d.MemberCount()); +} + +TEST(IStreamWrapper, fstream) { + fstream fs; + ASSERT_TRUE(Open(fs, "utf8bom.json")); + IStreamWrapper isw(fs); + EncodedInputStream, IStreamWrapper > eis(isw); + Document d; + EXPECT_TRUE(!d.ParseStream(eis).HasParseError()); + EXPECT_TRUE(d.IsObject()); + EXPECT_EQ(5, d.MemberCount()); +} + +// wifstream/wfstream only works on C++11 with codecvt_utf16 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include + +TEST(IStreamWrapper, wifstream) { + wifstream ifs; + ASSERT_TRUE(Open(ifs, "utf16bebom.json")); + ifs.imbue(std::locale(ifs.getloc(), + new std::codecvt_utf16)); + IStreamWrapper isw(ifs); + GenericDocument > d; + d.ParseStream, IStreamWrapper >(isw); + EXPECT_TRUE(!d.HasParseError()); + EXPECT_TRUE(d.IsObject()); + EXPECT_EQ(5, d.MemberCount()); +} + +TEST(IStreamWrapper, wfstream) { + wfstream fs; + ASSERT_TRUE(Open(fs, "utf16bebom.json")); + fs.imbue(std::locale(fs.getloc(), + new std::codecvt_utf16)); + IStreamWrapper isw(fs); + GenericDocument > d; + d.ParseStream, IStreamWrapper >(isw); + EXPECT_TRUE(!d.HasParseError()); + EXPECT_TRUE(d.IsObject()); + EXPECT_EQ(5, d.MemberCount()); +} + +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS From 67945ef727ee61ef319f81f3508c54c036d9453e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 7 Feb 2016 22:40:21 +0800 Subject: [PATCH 2/8] Disable including codecvt in tests as many libraries does not support it yet. --- test/unittest/istreamwrappertest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unittest/istreamwrappertest.cpp b/test/unittest/istreamwrappertest.cpp index 4b7c8035..942365b9 100644 --- a/test/unittest/istreamwrappertest.cpp +++ b/test/unittest/istreamwrappertest.cpp @@ -138,7 +138,8 @@ TEST(IStreamWrapper, fstream) { } // wifstream/wfstream only works on C++11 with codecvt_utf16 -#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +// But many C++11 library still not have it. +#if 0 #include TEST(IStreamWrapper, wifstream) { From ec81cc393bc6749fc75add4cdb11327575c33739 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 7 Feb 2016 22:54:02 +0800 Subject: [PATCH 3/8] Fix a IStreamWrapper test with incorrect type --- test/unittest/istreamwrappertest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/istreamwrappertest.cpp b/test/unittest/istreamwrappertest.cpp index 942365b9..9d9ff2f6 100644 --- a/test/unittest/istreamwrappertest.cpp +++ b/test/unittest/istreamwrappertest.cpp @@ -93,7 +93,7 @@ TEST(IStreamWrapper, wistringstream) { } TEST(IStreamWrapper, wstringstream) { - TestStringStream(); + TestStringStream(); } template From b9bca8e5c30991a5d26f5b8e904da4018737343e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 7 Feb 2016 23:30:51 +0800 Subject: [PATCH 4/8] Add OStreamWrapper --- include/rapidjson/ostreamwrapper.h | 69 +++++++++++++++++++++ test/unittest/CMakeLists.txt | 1 + test/unittest/ostreamwrappertest.cpp | 91 ++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 include/rapidjson/ostreamwrapper.h create mode 100644 test/unittest/ostreamwrappertest.cpp diff --git a/include/rapidjson/ostreamwrapper.h b/include/rapidjson/ostreamwrapper.h new file mode 100644 index 00000000..4cf407e9 --- /dev/null +++ b/include/rapidjson/ostreamwrapper.h @@ -0,0 +1,69 @@ +// 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. + +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::ostringstream + - \c std::stringstream + - \c std::wpstringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wofstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_ostream. +*/ + +template +class OStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + OStreamWrapper(StreamType& stream) : stream_(stream) {} + + void Put(Ch c) { + stream_.put(c); + } + + void Flush() { + stream_.flush(); + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + StreamType& stream_; +}; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index 728ccf1a..9c13816c 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -12,6 +12,7 @@ set(UNITTEST_SOURCES namespacetest.cpp pointertest.cpp prettywritertest.cpp + ostreamwrappertest.cpp readertest.cpp regextest.cpp schematest.cpp diff --git a/test/unittest/ostreamwrappertest.cpp b/test/unittest/ostreamwrappertest.cpp new file mode 100644 index 00000000..ba231bd9 --- /dev/null +++ b/test/unittest/ostreamwrappertest.cpp @@ -0,0 +1,91 @@ +// 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. + +#include "unittest.h" + +#include "rapidjson/ostreamwrapper.h" +#include "rapidjson/encodedstream.h" +#include "rapidjson/document.h" +#include +#include + +using namespace rapidjson; +using namespace std; + +template +static void TestStringStream() { + typedef typename StringStreamType::char_type Ch; + + Ch s[] = { 'A', 'B', 'C' }; + StringStreamType oss(s); + OStreamWrapper os(oss); + for (size_t i = 0; i < 3; i++) + os.Put(s[i]); + os.Flush(); + for (size_t i = 0; i < 3; i++) + EXPECT_EQ(s[i], oss.str()[i]); +} + +TEST(OStreamWrapper, ostringstream) { + TestStringStream(); +} + +TEST(OStreamWrapper, stringstream) { + TestStringStream(); +} + +TEST(OStreamWrapper, wostringstream) { + TestStringStream(); +} + +TEST(OStreamWrapper, wstringstream) { + TestStringStream(); +} + +TEST(OStreamWrapper, cout) { + OStreamWrapper os(cout); + const char* s = "Hello World!\n"; + while (*s) + os.Put(*s++); + os.Flush(); +} + +template +static void TestFileStream() { + char filename[L_tmpnam]; + FILE* fp = TempFile(filename); + fclose(fp); + + const char* s = "Hello World!\n"; + { + ofstream ofs(filename, ios::out | ios::binary); + OStreamWrapper osw(ofs); + for (const char* p = s; *p; p++) + osw.Put(*p); + osw.Flush(); + } + + fp = fopen(filename, "r"); + for (const char* p = s; *p; p++) + EXPECT_EQ(*p, static_cast(fgetc(fp))); + fclose(fp); +} + +TEST(OStreamWrapper, ofstream) { + TestFileStream(); +} + +TEST(OStreamWrapper, fstream) { + TestFileStream(); +} From c3133defb6cf5562920f5d80b2aee4e257d0429e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 8 Feb 2016 00:10:52 +0800 Subject: [PATCH 5/8] Renamed IStreamWrapper/OStreamWrapper --- include/rapidjson/istreamwrapper.h | 8 ++++++-- include/rapidjson/ostreamwrapper.h | 8 ++++++-- test/unittest/istreamwrappertest.cpp | 22 +++++++++++----------- test/unittest/ostreamwrappertest.cpp | 6 +++--- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h index 066fabd5..412509b9 100644 --- a/include/rapidjson/istreamwrapper.h +++ b/include/rapidjson/istreamwrapper.h @@ -13,6 +13,7 @@ // specific language governing permissions and limitations under the License. #include "stream.h" +#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -38,10 +39,10 @@ RAPIDJSON_NAMESPACE_BEGIN */ template -class IStreamWrapper { +class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; - IStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} + BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} Ch Peek() const { typename StreamType::int_type c = stream_.peek(); @@ -91,6 +92,9 @@ private: mutable Ch peekBuffer_[4]; }; +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/ostreamwrapper.h b/include/rapidjson/ostreamwrapper.h index 4cf407e9..127deb3e 100644 --- a/include/rapidjson/ostreamwrapper.h +++ b/include/rapidjson/ostreamwrapper.h @@ -13,6 +13,7 @@ // specific language governing permissions and limitations under the License. #include "stream.h" +#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -38,10 +39,10 @@ RAPIDJSON_NAMESPACE_BEGIN */ template -class OStreamWrapper { +class BasicOStreamWrapper { public: typedef typename StreamType::char_type Ch; - OStreamWrapper(StreamType& stream) : stream_(stream) {} + BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} void Put(Ch c) { stream_.put(c); @@ -62,6 +63,9 @@ private: StreamType& stream_; }; +typedef BasicOStreamWrapper OStreamWrapper; +typedef BasicOStreamWrapper WOStreamWrapper; + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/istreamwrappertest.cpp b/test/unittest/istreamwrappertest.cpp index 9d9ff2f6..f6b0fa91 100644 --- a/test/unittest/istreamwrappertest.cpp +++ b/test/unittest/istreamwrappertest.cpp @@ -29,7 +29,7 @@ static void TestStringStream() { { StringStreamType iss; - IStreamWrapper is(iss); + BasicIStreamWrapper is(iss); EXPECT_EQ(0, is.Tell()); if (sizeof(Ch) == 1) { EXPECT_EQ(0, is.Peek4()); @@ -43,7 +43,7 @@ static void TestStringStream() { { Ch s[] = { 'A', 'B', 'C', '\0' }; StringStreamType iss(s); - IStreamWrapper is(iss); + BasicIStreamWrapper is(iss); EXPECT_EQ(0, is.Tell()); if (sizeof(Ch) == 1) EXPECT_EQ(0, is.Peek4()); // less than 4 bytes @@ -61,7 +61,7 @@ static void TestStringStream() { { Ch s[] = { 'A', 'B', 'C', 'D', 'E', '\0' }; StringStreamType iss(s); - IStreamWrapper is(iss); + BasicIStreamWrapper is(iss); if (sizeof(Ch) == 1) { const Ch* c = is.Peek4(); for (int i = 0; i < 4; i++) @@ -118,8 +118,8 @@ static bool Open(FileStreamType& fs, const char* filename) { TEST(IStreamWrapper, ifstream) { ifstream ifs; ASSERT_TRUE(Open(ifs, "utf8bom.json")); - IStreamWrapper isw(ifs); - EncodedInputStream, IStreamWrapper > eis(isw); + IStreamWrapper isw(ifs); + EncodedInputStream, IStreamWrapper> eis(isw); Document d; EXPECT_TRUE(!d.ParseStream(eis).HasParseError()); EXPECT_TRUE(d.IsObject()); @@ -129,8 +129,8 @@ TEST(IStreamWrapper, ifstream) { TEST(IStreamWrapper, fstream) { fstream fs; ASSERT_TRUE(Open(fs, "utf8bom.json")); - IStreamWrapper isw(fs); - EncodedInputStream, IStreamWrapper > eis(isw); + IStreamWrapper isw(fs); + EncodedInputStream, IStreamWrapper> eis(isw); Document d; EXPECT_TRUE(!d.ParseStream(eis).HasParseError()); EXPECT_TRUE(d.IsObject()); @@ -147,9 +147,9 @@ TEST(IStreamWrapper, wifstream) { ASSERT_TRUE(Open(ifs, "utf16bebom.json")); ifs.imbue(std::locale(ifs.getloc(), new std::codecvt_utf16)); - IStreamWrapper isw(ifs); + WIStreamWrapper isw(ifs); GenericDocument > d; - d.ParseStream, IStreamWrapper >(isw); + d.ParseStream, WIStreamWrapper>(isw); EXPECT_TRUE(!d.HasParseError()); EXPECT_TRUE(d.IsObject()); EXPECT_EQ(5, d.MemberCount()); @@ -160,9 +160,9 @@ TEST(IStreamWrapper, wfstream) { ASSERT_TRUE(Open(fs, "utf16bebom.json")); fs.imbue(std::locale(fs.getloc(), new std::codecvt_utf16)); - IStreamWrapper isw(fs); + WIStreamWrapper isw(fs); GenericDocument > d; - d.ParseStream, IStreamWrapper >(isw); + d.ParseStream, WIStreamWrapper>(isw); EXPECT_TRUE(!d.HasParseError()); EXPECT_TRUE(d.IsObject()); EXPECT_EQ(5, d.MemberCount()); diff --git a/test/unittest/ostreamwrappertest.cpp b/test/unittest/ostreamwrappertest.cpp index ba231bd9..a94b9802 100644 --- a/test/unittest/ostreamwrappertest.cpp +++ b/test/unittest/ostreamwrappertest.cpp @@ -29,7 +29,7 @@ static void TestStringStream() { Ch s[] = { 'A', 'B', 'C' }; StringStreamType oss(s); - OStreamWrapper os(oss); + BasicOStreamWrapper os(oss); for (size_t i = 0; i < 3; i++) os.Put(s[i]); os.Flush(); @@ -54,7 +54,7 @@ TEST(OStreamWrapper, wstringstream) { } TEST(OStreamWrapper, cout) { - OStreamWrapper os(cout); + OStreamWrapper os(cout); const char* s = "Hello World!\n"; while (*s) os.Put(*s++); @@ -70,7 +70,7 @@ static void TestFileStream() { const char* s = "Hello World!\n"; { ofstream ofs(filename, ios::out | ios::binary); - OStreamWrapper osw(ofs); + BasicOStreamWrapper osw(ofs); for (const char* p = s; *p; p++) osw.Put(*p); osw.Flush(); From 562549fbac564b2e26f3ec858b0dd2603a428890 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 8 Feb 2016 00:45:55 +0800 Subject: [PATCH 6/8] Disable copy/assignment for stream wrappers --- include/rapidjson/istreamwrapper.h | 3 +++ include/rapidjson/ostreamwrapper.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h index 412509b9..9efeea24 100644 --- a/include/rapidjson/istreamwrapper.h +++ b/include/rapidjson/istreamwrapper.h @@ -87,6 +87,9 @@ public: } private: + BasicIStreamWrapper(const BasicIStreamWrapper&); + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + StreamType& stream_; size_t count_; //!< Number of characters read. Note: mutable Ch peekBuffer_[4]; diff --git a/include/rapidjson/ostreamwrapper.h b/include/rapidjson/ostreamwrapper.h index 127deb3e..8bf36dcd 100644 --- a/include/rapidjson/ostreamwrapper.h +++ b/include/rapidjson/ostreamwrapper.h @@ -60,6 +60,9 @@ public: size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: + BasicOStreamWrapper(const BasicOStreamWrapper&); + BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); + StreamType& stream_; }; From 0f7cb315ef20e655d5a1e47f5213702597c35746 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 8 Feb 2016 00:49:00 +0800 Subject: [PATCH 7/8] Update Stream.md --- doc/stream.md | 78 +++++++++++++++++++++++++++++++++++++-------- doc/stream.zh-cn.md | 74 +++++++++++++++++++++++++++++++++++------- 2 files changed, 128 insertions(+), 24 deletions(-) diff --git a/doc/stream.md b/doc/stream.md index 7b3c5ca3..b79ce537 100644 --- a/doc/stream.md +++ b/doc/stream.md @@ -119,6 +119,58 @@ fclose(fp); It can also directs the output to `stdout`. +# iostream Wrapper {#iostreamWrapper} + +Due to users' requests, RapidJSON provided official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above. + +## IStreamWrapper {#IStreamWrapper} + +`IStreamWrapper` wraps any class drived from `std::istream`, such as `std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, into RapidJSON's input stream. + +~~~cpp +#include +#include +#include + +using namespace rapidjson; +using namespace std; + +ifstream ifs("test.json"); +IStreamWrapper isw(ifs); + +Document d; +d.ParseStream(isw); +~~~ + +For classes derived from `std::wistream`, use `WIStreamWrapper`. + +## OStreamWrapper {#OStreamWrapper} + +Similarly, `OStreamWrapper` wraps any class derived from `std::ostream`, such as `std::ostringstream`, `std::stringstream`, `std::ofstream`, `std::fstream`, into RapidJSON's input stream. + +~~~cpp +#include +#include +#include +#include + +using namespace rapidjson; +using namespace std; + +Document d; +d.Parse(json); + +// ... + +ofstream ofs("output.json"); +OStreamWrapper osw(ofs); + +Writer writer(osw); +d.Accept(writer); +~~~ + +For classes derived from `std::wostream`, use `WOStreamWrapper`. + # Encoded Streams {#EncodedStreams} Encoded streams do not contain JSON itself, but they wrap byte streams to provide basic encoding/decoding function. @@ -277,14 +329,14 @@ There are two special interface, `PutBegin()` and `PutEnd()`, which are only for ## Example: istream wrapper {#ExampleIStreamWrapper} -The following example is a wrapper of `std::istream`, which only implements 3 functions. +The following example is a simple wrapper of `std::istream`, which only implements 3 functions. ~~~~~~~~~~cpp -class IStreamWrapper { +class MyIStreamWrapper { public: typedef char Ch; - IStreamWrapper(std::istream& is) : is_(is) { + MyIStreamWrapper(std::istream& is) : is_(is) { } Ch Peek() const { // 1 @@ -305,8 +357,8 @@ public: size_t PutEnd(Ch*) { assert(false); return 0; } private: - IStreamWrapper(const IStreamWrapper&); - IStreamWrapper& operator=(const IStreamWrapper&); + MyIStreamWrapper(const MyIStreamWrapper&); + MyIStreamWrapper& operator=(const MyIStreamWrapper&); std::istream& is_; }; @@ -317,7 +369,7 @@ User can use it to wrap instances of `std::stringstream`, `std::ifstream`. ~~~~~~~~~~cpp const char* json = "[1,2,3,4]"; std::stringstream ss(json); -IStreamWrapper is(ss); +MyIStreamWrapper is(ss); Document d; d.ParseStream(is); @@ -327,14 +379,14 @@ Note that, this implementation may not be as efficient as RapidJSON's memory or ## Example: ostream wrapper {#ExampleOStreamWrapper} -The following example is a wrapper of `std::istream`, which only implements 2 functions. +The following example is a simple wrapper of `std::istream`, which only implements 2 functions. ~~~~~~~~~~cpp -class OStreamWrapper { +class MyOStreamWrapper { public: typedef char Ch; - OStreamWrapper(std::ostream& os) : os_(os) { + MyOStreamWrapper(std::ostream& os) : os_(os) { } Ch Peek() const { assert(false); return '\0'; } @@ -347,8 +399,8 @@ public: size_t PutEnd(Ch*) { assert(false); return 0; } private: - OStreamWrapper(const OStreamWrapper&); - OStreamWrapper& operator=(const OStreamWrapper&); + MyOStreamWrapper(const MyOStreamWrapper&); + MyOStreamWrapper& operator=(const MyOStreamWrapper&); std::ostream& os_; }; @@ -361,9 +413,9 @@ Document d; // ... std::stringstream ss; -OSStreamWrapper os(ss); +MyOStreamWrapper os(ss); -Writer writer(os); +Writer writer(os); d.Accept(writer); ~~~~~~~~~~ diff --git a/doc/stream.zh-cn.md b/doc/stream.zh-cn.md index 0f930a90..5cc9c0d9 100644 --- a/doc/stream.zh-cn.md +++ b/doc/stream.zh-cn.md @@ -119,6 +119,58 @@ fclose(fp); 它也可以把输出导向`stdout`。 +# iostream 包装类 {#iostreamWrapper} + +基于用户的要求,RapidJSON提供了正式的 `std::basic_istream` 和 `std::basic_ostream` 包装类。然而,请注意其性能会大大低于以上的其他流。 + +## IStreamWrapper {#IStreamWrapper} + +`IStreamWrapper` 把任何继承自 `std::istream` 的类(如 `std::istringstream`、`std::stringstream`、`std::ifstream`、`std::fstream`)包装成 RapidJSON 的输入流。 + +~~~cpp +#include +#include +#include + +using namespace rapidjson; +using namespace std; + +ifstream ifs("test.json"); +IStreamWrapper isw(ifs); + +Document d; +d.ParseStream(isw); +~~~ + +对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。 + +## OStreamWrapper {#OStreamWrapper} + +相似地,`OStreamWrapper` 把任何继承自 `std::ostream` 的类(如 `std::ostringstream`、`std::stringstream`、`std::ofstream`、`std::fstream`)包装成 RapidJSON 的输出流。 + +~~~cpp +#include +#include +#include +#include + +using namespace rapidjson; +using namespace std; + +Document d; +d.Parse(json); + +// ... + +ofstream ofs("output.json"); +OStreamWrapper osw(ofs); + +Writer writer(osw); +d.Accept(writer); +~~~ + +对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。 + # 编码流 {#EncodedStreams} 编码流(encoded streams)本身不存储JSON,它们是通过包装字节流来提供基本的编码/解码功能。 @@ -277,14 +329,14 @@ concept Stream { ## 例子:istream的包装类 {#ExampleIStreamWrapper} -以下的例子是`std::istream`的包装类,它只需现3个函数。 +以下的简单例子是`std::istream`的包装类,它只需现3个函数。 ~~~~~~~~~~cpp -class IStreamWrapper { +class MyIStreamWrapper { public: typedef char Ch; - IStreamWrapper(std::istream& is) : is_(is) { + MyIStreamWrapper(std::istream& is) : is_(is) { } Ch Peek() const { // 1 @@ -305,8 +357,8 @@ public: size_t PutEnd(Ch*) { assert(false); return 0; } private: - IStreamWrapper(const IStreamWrapper&); - IStreamWrapper& operator=(const IStreamWrapper&); + MyIStreamWrapper(const MyIStreamWrapper&); + MyIStreamWrapper& operator=(const MyIStreamWrapper&); std::istream& is_; }; @@ -317,7 +369,7 @@ private: ~~~~~~~~~~cpp const char* json = "[1,2,3,4]"; std::stringstream ss(json); -IStreamWrapper is(ss); +MyIStreamWrapper is(ss); Document d; d.ParseStream(is); @@ -330,7 +382,7 @@ d.ParseStream(is); 以下的例子是`std::istream`的包装类,它只需实现2个函数。 ~~~~~~~~~~cpp -class OStreamWrapper { +class MyOStreamWrapper { public: typedef char Ch; @@ -347,8 +399,8 @@ public: size_t PutEnd(Ch*) { assert(false); return 0; } private: - OStreamWrapper(const OStreamWrapper&); - OStreamWrapper& operator=(const OStreamWrapper&); + MyOStreamWrapper(const MyOStreamWrapper&); + MyOStreamWrapper& operator=(const MyOStreamWrapper&); std::ostream& os_; }; @@ -361,9 +413,9 @@ Document d; // ... std::stringstream ss; -OSStreamWrapper os(ss); +MyOStreamWrapper os(ss); -Writer writer(os); +Writer writer(os); d.Accept(writer); ~~~~~~~~~~ From 953dd5a34f27f0fbc87dc4a50ad30d4ba842e6e6 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 8 Feb 2016 01:45:12 +0800 Subject: [PATCH 8/8] Fix OStreamWrapper test --- test/unittest/ostreamwrappertest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/ostreamwrappertest.cpp b/test/unittest/ostreamwrappertest.cpp index a94b9802..b1d1cd82 100644 --- a/test/unittest/ostreamwrappertest.cpp +++ b/test/unittest/ostreamwrappertest.cpp @@ -27,7 +27,7 @@ template static void TestStringStream() { typedef typename StringStreamType::char_type Ch; - Ch s[] = { 'A', 'B', 'C' }; + Ch s[] = { 'A', 'B', 'C', '\0' }; StringStreamType oss(s); BasicOStreamWrapper os(oss); for (size_t i = 0; i < 3; i++)