Base buffered BasicIStreamWrapper on the original (better performing) FileReadStream algorithm.

This commit is contained in:
ylavic 2018-12-06 00:21:05 +01:00
parent 124e8b6079
commit 8aab3db129
3 changed files with 73 additions and 124 deletions

View File

@ -17,7 +17,6 @@
#include "stream.h" #include "stream.h"
#include <cstdio> #include <cstdio>
#include <cstring>
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -36,42 +35,21 @@ class FileReadStream {
public: public:
typedef char Ch; //!< Character type (byte). 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. //! Constructor.
/*! /*!
\param fp File pointer opened for read. \param fp File pointer opened for read.
\param buffer user-supplied buffer. \param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \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_() { 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 && buffer_ != 0 && size_ > 0); RAPIDJSON_ASSERT(fp_ != 0);
if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) { RAPIDJSON_ASSERT(bufferSize >= 4);
size_ = sizeof(peekBuffer_) / sizeof(Ch); Read();
buffer_ = peekBuffer_;
}
} }
Ch Peek() const { Ch Peek() const { return *current_; }
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) Ch Take() { Ch c = *current_; Read(); return c; }
return static_cast<Ch>('\0'); size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
return buffer_[pos_];
}
Ch Take() {
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read())
return static_cast<Ch>('\0');
return buffer_[pos_++];
}
size_t Tell() const { return count_ + pos_; }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
@ -81,36 +59,35 @@ public:
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const {
if (len_ - pos_ < 4) { return (current_ + 4 <= bufferLast_) ? current_ : 0;
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: private:
FileReadStream(); void Read() {
FileReadStream(const FileReadStream&); if (current_ < bufferLast_)
FileReadStream& operator=(const FileReadStream&); ++current_;
else if (!eof_) {
count_ += readCount_;
readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
size_t Read() const { if (readCount_ < bufferSize_) {
count_ += pos_; buffer_[readCount_] = '\0';
pos_ = 0; ++bufferLast_;
len_ = std::fread(buffer_, sizeof(Ch), size_, fp_); eof_ = true;
return len_; }
}
} }
std::FILE* fp_; std::FILE* fp_;
Ch peekBuffer_[4], *buffer_; Ch *buffer_;
size_t size_; size_t bufferSize_;
mutable size_t pos_, len_, count_; Ch *bufferLast_;
Ch *current_;
size_t readCount_;
size_t count_; //!< Number of characters read
bool eof_;
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -17,7 +17,6 @@
#include "stream.h" #include "stream.h"
#include <iosfwd> #include <iosfwd>
#include <cstring>
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -50,76 +49,70 @@ class BasicIStreamWrapper {
public: public:
typedef typename StreamType::char_type Ch; typedef typename StreamType::char_type Ch;
BasicIStreamWrapper(StreamType& stream) : stream_(stream), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_() {} //! Constructor.
/*!
BasicIStreamWrapper(StreamType& stream, Ch *buffer, size_t size) : stream_(stream), buffer_(buffer), size_(size), pos_(), len_(), count_() { \param stream stream opened for read.
RAPIDJSON_ASSERT(buffer_ != 0 && static_cast<std::streamsize>(size_) > 0); */
if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) { BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
size_ = sizeof(peekBuffer_) / sizeof(Ch); Read();
buffer_ = peekBuffer_;
}
} }
Ch Peek() const { //! Constructor.
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) /*!
return static_cast<Ch>('\0'); \param stream stream opened for read.
return buffer_[pos_]; \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() { Ch Peek() const { return *current_; }
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read()) Ch Take() { Ch c = *current_; Read(); return c; }
return static_cast<Ch>('\0'); size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
return buffer_[pos_++];
}
// tellg() may return -1 when failed. So we count by ourself.
size_t Tell() const { return count_ + pos_; }
// Not implemented // Not implemented
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); } 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; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const {
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
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<std::streamsize>(size_ - len_))) {
len_ += static_cast<size_t>(stream_.gcount());
if (len_ < 4)
return 0;
}
else
len_ = size_;
}
return &buffer_[pos_];
} }
private: private:
BasicIStreamWrapper();
BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper(const BasicIStreamWrapper&);
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
size_t Read() const { void Read() {
count_ += pos_; if (current_ < bufferLast_)
pos_ = 0; ++current_;
if (!stream_.read(buffer_, static_cast<std::streamsize>(size_))) else if (!eof_) {
len_ = static_cast<size_t>(stream_.gcount()); count_ += readCount_;
else readCount_ = bufferSize_;
len_ = size_; bufferLast_ = buffer_ + readCount_ - 1;
return len_; current_ = buffer_;
if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
readCount_ = static_cast<size_t>(stream_.gcount());
*(bufferLast_ = buffer_ + readCount_) = '\0';
eof_ = true;
}
}
} }
StreamType &stream_; StreamType &stream_;
Ch peekBuffer_[4], *buffer_; Ch peekBuffer_[4], *buffer_;
size_t size_; size_t bufferSize_;
mutable size_t pos_, len_, count_; Ch *bufferLast_;
Ch *current_;
size_t readCount_;
size_t count_; //!< Number of characters read
bool eof_;
}; };
typedef BasicIStreamWrapper<std::istream> IStreamWrapper; typedef BasicIStreamWrapper<std::istream> IStreamWrapper;

View File

@ -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)) { TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
for (size_t i = 0; i < kTrialCount; i++) { for (size_t i = 0; i < kTrialCount; i++) {
FILE *fp = fopen(filename_, "rb"); 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) { TEST_F(RapidJson, IStreamWrapper) {
for (size_t i = 0; i < kTrialCount; i++) { for (size_t i = 0; i < kTrialCount; i++) {
std::ifstream is(filename_, std::ios::in | std::ios::binary); std::ifstream is(filename_, std::ios::in | std::ios::binary);