From 04515a639e48d46d7abbd45b2cf6462ea681ac62 Mon Sep 17 00:00:00 2001 From: "miloyip@gmail.com" Date: Mon, 21 Nov 2011 10:00:33 +0000 Subject: [PATCH] Implemented FileWriteStream with buffering git-svn-id: https://rapidjson.googlecode.com/svn/trunk@23 c5894555-1306-4e8d-425f-1f6f381ee07c --- example/condense/condense.cpp | 11 +++-- example/pretty/pretty.cpp | 11 +++-- include/rapidjson/filereadstream.h | 1 - include/rapidjson/filestream.h | 4 +- include/rapidjson/filewritestream.h | 73 +++++++++++++++++++++++++++++ test/unittest/filestreamtest.cpp | 40 ++++++++++++---- 6 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 include/rapidjson/filewritestream.h diff --git a/example/condense/condense.cpp b/example/condense/condense.cpp index 262dbd7..22c882e 100644 --- a/example/condense/condense.cpp +++ b/example/condense/condense.cpp @@ -5,18 +5,21 @@ #include "rapidjson/reader.h" #include "rapidjson/writer.h" -#include "rapidjson/filestream.h" +#include "rapidjson/filereadstream.h" +#include "rapidjson/filewritestream.h" using namespace rapidjson; int main(int argc, char* argv[]) { // Prepare JSON reader and input stream. Reader reader; - FileStream is(stdin); + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); // Prepare JSON writer and output stream. - FileStream os(stdout); - Writer writer(os); + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + Writer writer(os); // JSON reader parse from the input stream and let writer generate the output. if (!reader.Parse<0>(is, writer)) { diff --git a/example/pretty/pretty.cpp b/example/pretty/pretty.cpp index f34db43..dae41b4 100644 --- a/example/pretty/pretty.cpp +++ b/example/pretty/pretty.cpp @@ -2,18 +2,21 @@ #include "rapidjson/reader.h" #include "rapidjson/prettywriter.h" -#include "rapidjson/filestream.h" +#include "rapidjson/filereadstream.h" +#include "rapidjson/filewritestream.h" using namespace rapidjson; int main(int argc, char* argv[]) { // Prepare reader and input stream. Reader reader; - FileStream is(stdin); + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); // Prepare writer and output stream. - FileStream os(stdout); - PrettyWriter writer(os); + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + PrettyWriter writer(os); // JSON reader parse from the input stream and let writer generate the output. if (!reader.Parse<0>(is, writer)) { diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index a926fde..284c931 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -46,7 +46,6 @@ private: if (readCount_ < bufferSize_) { buffer_[readCount_] = '\0'; ++bufferLast_; - ++count_; eof_ = true; } } diff --git a/include/rapidjson/filestream.h b/include/rapidjson/filestream.h index e3201c4..86d3f56 100644 --- a/include/rapidjson/filestream.h +++ b/include/rapidjson/filestream.h @@ -34,10 +34,8 @@ private: current_ = (char)c; count_++; } - else if (current_ != '\0') { + else if (current_ != '\0') current_ = '\0'; - count_++; - } } FILE* fp_; diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h new file mode 100644 index 0000000..6eca68d --- /dev/null +++ b/include/rapidjson/filewritestream.h @@ -0,0 +1,73 @@ +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ + +#include "rapidjson.h" +#include + +namespace rapidjson { + +//! Wrapper of C file stream for input using fread(). +/*! + \implements Stream +*/ +class FileWriteStream { +public: + typedef char Ch; //!< Character type. Only support char. + + FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { + RAPIDJSON_ASSERT(fp_ != 0); + } + + void Put(char c) { + if (current_ >= bufferEnd_) + Flush(); + + *current_++ = c; + } + + void PutN(char c, size_t n) { + size_t avail = bufferEnd_ - current_; + while (n > avail) { + memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = bufferEnd_ - current_; + } + + if (n > 0) { + memset(current_, c, n); + current_ += n; + } + } + + void Flush() { + if (current_ != buffer_) { + fwrite(buffer_, 1, current_ - buffer_, fp_); + current_ = buffer_; + } + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); } + char Take() { RAPIDJSON_ASSERT(false); } + size_t Tell() const { RAPIDJSON_ASSERT(false); } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + FILE* fp_; + char *buffer_; + char *bufferEnd_; + char *current_; +}; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(FileWriteStream& stream, char c, size_t n) { + stream.PutN(c, n); +} + +} // namespace rapidjson + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/test/unittest/filestreamtest.cpp b/test/unittest/filestreamtest.cpp index cc19798..a154769 100644 --- a/test/unittest/filestreamtest.cpp +++ b/test/unittest/filestreamtest.cpp @@ -1,6 +1,7 @@ #include "unittest.h" #include "rapidjson/filestream.h" #include "rapidjson/filereadstream.h" +#include "rapidjson/filewritestream.h" using namespace rapidjson; @@ -17,7 +18,6 @@ class FileStreamTest : public ::testing::Test { json_ = (char*)malloc(length_ + 1); fread(json_, 1, length_, fp); json_[length_] = '\0'; - length_++; // include the null terminator fclose(fp); } @@ -31,7 +31,7 @@ protected: size_t length_; }; -TEST_F(FileStreamTest, Read) { +TEST_F(FileStreamTest, FileStream_Read) { FILE *fp = fopen(filename_, "rb"); ASSERT_TRUE(fp != 0); FileStream s(fp); @@ -48,18 +48,16 @@ TEST_F(FileStreamTest, Read) { fclose(fp); } -TEST_F(FileStreamTest, BufferedRead) { +TEST_F(FileStreamTest, FileReadStream) { FILE *fp = fopen(filename_, "rb"); ASSERT_TRUE(fp != 0); char buffer[65536]; FileReadStream s(fp, buffer, sizeof(buffer)); for (size_t i = 0; i < length_; i++) { - if (json_[i] != s.Peek()) - __asm int 3; - ASSERT_EQ(json_[i], s.Peek()); - ASSERT_EQ(json_[i], s.Peek()); // 2nd time should be the same - ASSERT_EQ(json_[i], s.Take()); + EXPECT_EQ(json_[i], s.Peek()); + EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same + EXPECT_EQ(json_[i], s.Take()); } EXPECT_EQ(length_, s.Tell()); @@ -67,3 +65,29 @@ TEST_F(FileStreamTest, BufferedRead) { fclose(fp); } + +TEST_F(FileStreamTest, FileWriteStream) { + char filename[L_tmpnam]; + tmpnam(filename); + + FILE *fp = fopen(filename, "wb"); + char buffer[65536]; + FileWriteStream os(fp, buffer, sizeof(buffer)); + for (size_t i = 0; i < length_; i++) + os.Put(json_[i]); + os.Flush(); + fclose(fp); + + // Read it back to verify + fp = fopen(filename, "rb"); + FileReadStream is(fp, buffer, sizeof(buffer)); + + for (size_t i = 0; i < length_; i++) + EXPECT_EQ(json_[i], is.Take()); + + EXPECT_EQ(length_, is.Tell()); + fclose(fp); + + //std::cout << filename << std::endl; + remove(filename); +}