From 2498c5776f754dc61a1ebbbddd5a7096e5eda62e Mon Sep 17 00:00:00 2001 From: ylavic Date: Wed, 5 Dec 2018 16:06:12 +0100 Subject: [PATCH 1/3] Optimize FileReadStream and BasicIStreamWrapper. On (my) linux, perftest reports: - ~40% gain for FileReadStream (Take() loop), - ~10% gain for ReaderParse_DummyHandler_FileReadStream. With the same logic applied to BasicIStreamWrapper, which thus can now also be created with a user buffer, performances align with those of FileReadStream (same buffer size). The "unbuffered" versions (added for FileReadStream) work solely with the internal peekBuffer (Ch[4]) and are measured in perftest. When performances don't matter much, they can avoid the use of large stack/heap buffers. --- include/rapidjson/filereadstream.h | 81 ++++++++++++++++--------- include/rapidjson/istreamwrapper.h | 75 ++++++++++++++--------- test/perftest/rapidjsontest.cpp | 95 ++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 56 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index f1bfb7d..d468ba1 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -17,6 +17,7 @@ #include "stream.h" #include +#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -35,21 +36,42 @@ class FileReadStream { public: typedef char Ch; //!< Character type (byte). + //! Constructor. + /*! + \param fp File pointer opened for read. + */ + FileReadStream(std::FILE* fp) : fp_(fp), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_() + { + RAPIDJSON_ASSERT(fp_ != 0); + } + //! Constructor. /*! \param fp File pointer opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ - FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(fp_ != 0); - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); + FileReadStream(std::FILE* fp, Ch *buffer, size_t size) : fp_(fp), buffer_(buffer), size_(size), pos_(), len_(), count_() { + RAPIDJSON_ASSERT(fp_ != 0 && buffer_ != 0 && size_ > 0); + if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) { + size_ = sizeof(peekBuffer_) / sizeof(Ch); + buffer_ = peekBuffer_; + } } - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + Ch Peek() const { + if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) + return static_cast('\0'); + return buffer_[pos_]; + } + + Ch Take() { + if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) + return static_cast('\0'); + return buffer_[pos_++]; + } + + size_t Tell() const { return count_ + pos_; } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } @@ -59,35 +81,36 @@ public: // For encoding detection only. const Ch* Peek4() const { - return (current_ + 4 <= bufferLast_) ? current_ : 0; + if (len_ - pos_ < 4) { + if (pos_) { + len_ -= pos_; + std::memmove(buffer_, buffer_ + pos_, len_); + count_ += pos_; + pos_ = 0; + } + len_ += std::fread(buffer_ + len_, sizeof(Ch), size_ - len_, fp_); + if (len_ < 4) + return 0; + } + return &buffer_[pos_]; } private: - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; + FileReadStream(); + FileReadStream(const FileReadStream&); + FileReadStream& operator=(const FileReadStream&); - if (readCount_ < bufferSize_) { - buffer_[readCount_] = '\0'; - ++bufferLast_; - eof_ = true; - } - } + size_t Read() const { + count_ += pos_; + pos_ = 0; + len_ = std::fread(buffer_, sizeof(Ch), size_, fp_); + return len_; } std::FILE* fp_; - Ch *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; + Ch peekBuffer_[4], *buffer_; + size_t size_; + mutable size_t pos_, len_, count_; }; RAPIDJSON_NAMESPACE_END diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h index 5f81698..0eac7f4 100644 --- a/include/rapidjson/istreamwrapper.h +++ b/include/rapidjson/istreamwrapper.h @@ -17,6 +17,7 @@ #include "stream.h" #include +#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -48,26 +49,33 @@ template class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; - BasicIStreamWrapper(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) : static_cast('\0'); + BasicIStreamWrapper(StreamType& stream) : stream_(stream), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_() {} + + BasicIStreamWrapper(StreamType& stream, Ch *buffer, size_t size) : stream_(stream), buffer_(buffer), size_(size), pos_(), len_(), count_() { + RAPIDJSON_ASSERT(buffer_ != 0 && static_cast(size_) > 0); + if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) { + size_ = sizeof(peekBuffer_) / sizeof(Ch); + buffer_ = peekBuffer_; + } } - 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'; + Ch Peek() const { + if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) + return static_cast('\0'); + return buffer_[pos_]; + } + + Ch Take() { + if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) + return static_cast('\0'); + return buffer_[pos_++]; } // tellg() may return -1 when failed. So we count by ourself. - size_t Tell() const { return count_; } + size_t Tell() const { return count_ + pos_; } + // Not implemented Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } @@ -76,29 +84,42 @@ public: // 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; + if (len_ - pos_ < 4) { + if (pos_) { + len_ -= pos_; + std::memmove(buffer_, buffer_ + pos_, len_); + count_ += pos_; + pos_ = 0; } - peekBuffer_[i] = static_cast(c); + if (!stream_.read(buffer_ + len_, static_cast(size_ - len_))) { + len_ += static_cast(stream_.gcount()); + if (len_ < 4) + return 0; + } + else + len_ = size_; } - for (--i; i >= 0; --i) - stream_.putback(peekBuffer_[i]); - return !hasError ? peekBuffer_ : 0; + return &buffer_[pos_]; } private: BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + size_t Read() const { + count_ += pos_; + pos_ = 0; + if (!stream_.read(buffer_, static_cast(size_))) + len_ = static_cast(stream_.gcount()); + else + len_ = size_; + return len_; + } + StreamType& stream_; - size_t count_; //!< Number of characters read. Note: - mutable Ch peekBuffer_[4]; + Ch peekBuffer_[4], *buffer_; + size_t size_; + mutable size_t pos_, len_, count_; }; typedef BasicIStreamWrapper IStreamWrapper; diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index a11a557..e1224df 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -21,9 +21,12 @@ #include "rapidjson/prettywriter.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/filereadstream.h" +#include "rapidjson/istreamwrapper.h" #include "rapidjson/encodedstream.h" #include "rapidjson/memorystream.h" +#include + #ifdef RAPIDJSON_SSE2 #define SIMD_SUFFIX(name) name##_SSE2 #elif defined(RAPIDJSON_SSE42) @@ -451,6 +454,16 @@ TEST_F(RapidJson, FileReadStream) { } } +TEST_F(RapidJson, FileReadStream_Unbuffered) { + for (size_t i = 0; i < kTrialCount; i++) { + FILE *fp = fopen(filename_, "rb"); + FileReadStream s(fp); + while (s.Take() != '\0') + ; + fclose(fp); + } +} + TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { for (size_t i = 0; i < kTrialCount; i++) { FILE *fp = fopen(filename_, "rb"); @@ -463,6 +476,88 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { } } +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream_Unbuffered)) { + for (size_t i = 0; i < kTrialCount; i++) { + FILE *fp = fopen(filename_, "rb"); + FileReadStream s(fp); + BaseReaderHandler<> h; + Reader reader; + reader.Parse(s, h); + fclose(fp); + } +} + +TEST_F(RapidJson, IStreamWrapper) { + for (size_t i = 0; i < kTrialCount; i++) { + std::ifstream is(filename_); + char buffer[65536]; + IStreamWrapper isw(is, buffer, sizeof(buffer)); + while (isw.Take() != '\0') + ; + is.close(); + } +} + +TEST_F(RapidJson, IStreamWrapper_Unbuffered) { + for (size_t i = 0; i < kTrialCount; i++) { + std::ifstream is(filename_); + IStreamWrapper isw(is); + while (isw.Take() != '\0') + ; + is.close(); + } +} + +TEST_F(RapidJson, IStreamWrapper_Setbuffered) { + for (size_t i = 0; i < kTrialCount; i++) { + std::ifstream is; + char buffer[65536]; + is.rdbuf()->pubsetbuf(buffer, sizeof(buffer)); + is.open(filename_); + IStreamWrapper isw(is); + while (isw.Take() != '\0') + ; + is.close(); + } +} + +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper)) { + for (size_t i = 0; i < kTrialCount; i++) { + std::ifstream is(filename_); + char buffer[65536]; + IStreamWrapper isw(is, buffer, sizeof(buffer)); + BaseReaderHandler<> h; + Reader reader; + reader.Parse(isw, h); + is.close(); + } +} + +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Unbuffered)) { + for (size_t i = 0; i < kTrialCount; i++) { + std::ifstream is(filename_); + IStreamWrapper isw(is); + BaseReaderHandler<> h; + Reader reader; + reader.Parse(isw, h); + is.close(); + } +} + +TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Setbuffered)) { + for (size_t i = 0; i < kTrialCount; i++) { + std::ifstream is; + char buffer[65536]; + is.rdbuf()->pubsetbuf(buffer, sizeof(buffer)); + is.open(filename_); + IStreamWrapper isw(is); + BaseReaderHandler<> h; + Reader reader; + reader.Parse(isw, h); + is.close(); + } +} + TEST_F(RapidJson, StringBuffer) { StringBuffer sb; for (int i = 0; i < 32 * 1024 * 1024; i++) From 124e8b6079eaa6f8b6221b43e4e149c406d36636 Mon Sep 17 00:00:00 2001 From: ylavic Date: Wed, 5 Dec 2018 18:35:45 +0100 Subject: [PATCH 2/3] Possibly std::ios::binary helps with streams on Windows --- test/perftest/rapidjsontest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index e1224df..785c1a2 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -489,7 +489,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream_Unbuffered TEST_F(RapidJson, IStreamWrapper) { for (size_t i = 0; i < kTrialCount; i++) { - std::ifstream is(filename_); + std::ifstream is(filename_, std::ios::in | std::ios::binary); char buffer[65536]; IStreamWrapper isw(is, buffer, sizeof(buffer)); while (isw.Take() != '\0') @@ -500,7 +500,7 @@ TEST_F(RapidJson, IStreamWrapper) { TEST_F(RapidJson, IStreamWrapper_Unbuffered) { for (size_t i = 0; i < kTrialCount; i++) { - std::ifstream is(filename_); + std::ifstream is(filename_, std::ios::in | std::ios::binary); IStreamWrapper isw(is); while (isw.Take() != '\0') ; @@ -513,7 +513,7 @@ TEST_F(RapidJson, IStreamWrapper_Setbuffered) { std::ifstream is; char buffer[65536]; is.rdbuf()->pubsetbuf(buffer, sizeof(buffer)); - is.open(filename_); + is.open(filename_, std::ios::in | std::ios::binary); IStreamWrapper isw(is); while (isw.Take() != '\0') ; @@ -523,7 +523,7 @@ TEST_F(RapidJson, IStreamWrapper_Setbuffered) { TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper)) { for (size_t i = 0; i < kTrialCount; i++) { - std::ifstream is(filename_); + std::ifstream is(filename_, std::ios::in | std::ios::binary); char buffer[65536]; IStreamWrapper isw(is, buffer, sizeof(buffer)); BaseReaderHandler<> h; @@ -535,7 +535,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper)) { TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Unbuffered)) { for (size_t i = 0; i < kTrialCount; i++) { - std::ifstream is(filename_); + std::ifstream is(filename_, std::ios::in | std::ios::binary); IStreamWrapper isw(is); BaseReaderHandler<> h; Reader reader; @@ -549,7 +549,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Setbuffere std::ifstream is; char buffer[65536]; is.rdbuf()->pubsetbuf(buffer, sizeof(buffer)); - is.open(filename_); + is.open(filename_, std::ios::in | std::ios::binary); IStreamWrapper isw(is); BaseReaderHandler<> h; Reader reader; From 8aab3db129585d81d74ed5108450c874622d46fd Mon Sep 17 00:00:00 2001 From: ylavic Date: Thu, 6 Dec 2018 00:21:05 +0100 Subject: [PATCH 3/3] Base buffered BasicIStreamWrapper on the original (better performing) FileReadStream algorithm. --- include/rapidjson/filereadstream.h | 81 +++++++++---------------- include/rapidjson/istreamwrapper.h | 95 ++++++++++++++---------------- test/perftest/rapidjsontest.cpp | 21 ------- 3 files changed, 73 insertions(+), 124 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index d468ba1..f1bfb7d 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -17,7 +17,6 @@ #include "stream.h" #include -#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -36,42 +35,21 @@ class FileReadStream { public: typedef char Ch; //!< Character type (byte). - //! Constructor. - /*! - \param fp File pointer opened for read. - */ - FileReadStream(std::FILE* fp) : fp_(fp), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_() - { - RAPIDJSON_ASSERT(fp_ != 0); - } - //! Constructor. /*! \param fp File pointer opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ - FileReadStream(std::FILE* fp, Ch *buffer, size_t size) : fp_(fp), buffer_(buffer), size_(size), pos_(), len_(), count_() { - RAPIDJSON_ASSERT(fp_ != 0 && buffer_ != 0 && size_ > 0); - if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) { - size_ = sizeof(peekBuffer_) / sizeof(Ch); - buffer_ = peekBuffer_; - } + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); } - Ch Peek() const { - if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) - return static_cast('\0'); - return buffer_[pos_]; - } - - Ch Take() { - if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) - return static_cast('\0'); - return buffer_[pos_++]; - } - - size_t Tell() const { return count_ + pos_; } + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } @@ -81,36 +59,35 @@ public: // For encoding detection only. const Ch* Peek4() const { - if (len_ - pos_ < 4) { - if (pos_) { - len_ -= pos_; - std::memmove(buffer_, buffer_ + pos_, len_); - count_ += pos_; - pos_ = 0; - } - len_ += std::fread(buffer_ + len_, sizeof(Ch), size_ - len_, fp_); - if (len_ < 4) - return 0; - } - return &buffer_[pos_]; + return (current_ + 4 <= bufferLast_) ? current_ : 0; } private: - FileReadStream(); - FileReadStream(const FileReadStream&); - FileReadStream& operator=(const FileReadStream&); + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; - size_t Read() const { - count_ += pos_; - pos_ = 0; - len_ = std::fread(buffer_, sizeof(Ch), size_, fp_); - return len_; + if (readCount_ < bufferSize_) { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } } std::FILE* fp_; - Ch peekBuffer_[4], *buffer_; - size_t size_; - mutable size_t pos_, len_, count_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; }; RAPIDJSON_NAMESPACE_END diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h index 0eac7f4..f304fb0 100644 --- a/include/rapidjson/istreamwrapper.h +++ b/include/rapidjson/istreamwrapper.h @@ -17,7 +17,6 @@ #include "stream.h" #include -#include #ifdef __clang__ RAPIDJSON_DIAG_PUSH @@ -50,76 +49,70 @@ class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; - BasicIStreamWrapper(StreamType& stream) : stream_(stream), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_() {} - - BasicIStreamWrapper(StreamType& stream, Ch *buffer, size_t size) : stream_(stream), buffer_(buffer), size_(size), pos_(), len_(), count_() { - RAPIDJSON_ASSERT(buffer_ != 0 && static_cast(size_) > 0); - if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) { - size_ = sizeof(peekBuffer_) / sizeof(Ch); - buffer_ = peekBuffer_; - } + //! Constructor. + /*! + \param stream stream opened for read. + */ + BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + Read(); } - Ch Peek() const { - if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) - return static_cast('\0'); - return buffer_[pos_]; + //! Constructor. + /*! + \param stream stream opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); } - Ch Take() { - if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) - return static_cast('\0'); - return buffer_[pos_++]; - } - - // tellg() may return -1 when failed. So we count by ourself. - size_t Tell() const { return count_ + pos_; } + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 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. - if (len_ - pos_ < 4) { - if (pos_) { - len_ -= pos_; - std::memmove(buffer_, buffer_ + pos_, len_); - count_ += pos_; - pos_ = 0; - } - if (!stream_.read(buffer_ + len_, static_cast(size_ - len_))) { - len_ += static_cast(stream_.gcount()); - if (len_ < 4) - return 0; - } - else - len_ = size_; - } - return &buffer_[pos_]; + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: + BasicIStreamWrapper(); BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - size_t Read() const { - count_ += pos_; - pos_ = 0; - if (!stream_.read(buffer_, static_cast(size_))) - len_ = static_cast(stream_.gcount()); - else - len_ = size_; - return len_; + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = bufferSize_; + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (!stream_.read(buffer_, static_cast(bufferSize_))) { + readCount_ = static_cast(stream_.gcount()); + *(bufferLast_ = buffer_ + readCount_) = '\0'; + eof_ = true; + } + } } - StreamType& stream_; + StreamType &stream_; Ch peekBuffer_[4], *buffer_; - size_t size_; - mutable size_t pos_, len_, count_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; }; typedef BasicIStreamWrapper IStreamWrapper; diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 785c1a2..9492cc5 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -454,16 +454,6 @@ TEST_F(RapidJson, FileReadStream) { } } -TEST_F(RapidJson, FileReadStream_Unbuffered) { - for (size_t i = 0; i < kTrialCount; i++) { - FILE *fp = fopen(filename_, "rb"); - FileReadStream s(fp); - while (s.Take() != '\0') - ; - fclose(fp); - } -} - TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { for (size_t i = 0; i < kTrialCount; i++) { FILE *fp = fopen(filename_, "rb"); @@ -476,17 +466,6 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { } } -TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream_Unbuffered)) { - for (size_t i = 0; i < kTrialCount; i++) { - FILE *fp = fopen(filename_, "rb"); - FileReadStream s(fp); - BaseReaderHandler<> h; - Reader reader; - reader.Parse(s, h); - fclose(fp); - } -} - TEST_F(RapidJson, IStreamWrapper) { for (size_t i = 0; i < kTrialCount; i++) { std::ifstream is(filename_, std::ios::in | std::ios::binary);