Skip to content

Commit 8aab3db

Browse files
committed
Base buffered BasicIStreamWrapper on the original (better performing) FileReadStream algorithm.
1 parent 124e8b6 commit 8aab3db

File tree

3 files changed

+74
-125
lines changed

3 files changed

+74
-125
lines changed

include/rapidjson/filereadstream.h

Lines changed: 30 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include "stream.h"
1919
#include <cstdio>
20-
#include <cstring>
2120

2221
#ifdef __clang__
2322
RAPIDJSON_DIAG_PUSH
@@ -36,42 +35,21 @@ class FileReadStream {
3635
public:
3736
typedef char Ch; //!< Character type (byte).
3837

39-
//! Constructor.
40-
/*!
41-
\param fp File pointer opened for read.
42-
*/
43-
FileReadStream(std::FILE* fp) : fp_(fp), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_()
44-
{
45-
RAPIDJSON_ASSERT(fp_ != 0);
46-
}
47-
4838
//! Constructor.
4939
/*!
5040
\param fp File pointer opened for read.
5141
\param buffer user-supplied buffer.
5242
\param bufferSize size of buffer in bytes. Must >=4 bytes.
5343
*/
54-
FileReadStream(std::FILE* fp, Ch *buffer, size_t size) : fp_(fp), buffer_(buffer), size_(size), pos_(), len_(), count_() {
55-
RAPIDJSON_ASSERT(fp_ != 0 && buffer_ != 0 && size_ > 0);
56-
if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) {
57-
size_ = sizeof(peekBuffer_) / sizeof(Ch);
58-
buffer_ = peekBuffer_;
59-
}
60-
}
61-
62-
Ch Peek() const {
63-
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read())
64-
return static_cast<Ch>('\0');
65-
return buffer_[pos_];
66-
}
67-
68-
Ch Take() {
69-
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read())
70-
return static_cast<Ch>('\0');
71-
return buffer_[pos_++];
44+
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) {
45+
RAPIDJSON_ASSERT(fp_ != 0);
46+
RAPIDJSON_ASSERT(bufferSize >= 4);
47+
Read();
7248
}
7349

74-
size_t Tell() const { return count_ + pos_; }
50+
Ch Peek() const { return *current_; }
51+
Ch Take() { Ch c = *current_; Read(); return c; }
52+
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
7553

7654
// Not implemented
7755
void Put(Ch) { RAPIDJSON_ASSERT(false); }
@@ -81,36 +59,35 @@ class FileReadStream {
8159

8260
// For encoding detection only.
8361
const Ch* Peek4() const {
84-
if (len_ - pos_ < 4) {
85-
if (pos_) {
86-
len_ -= pos_;
87-
std::memmove(buffer_, buffer_ + pos_, len_);
88-
count_ += pos_;
89-
pos_ = 0;
90-
}
91-
len_ += std::fread(buffer_ + len_, sizeof(Ch), size_ - len_, fp_);
92-
if (len_ < 4)
93-
return 0;
94-
}
95-
return &buffer_[pos_];
62+
return (current_ + 4 <= bufferLast_) ? current_ : 0;
9663
}
9764

9865
private:
99-
FileReadStream();
100-
FileReadStream(const FileReadStream&);
101-
FileReadStream& operator=(const FileReadStream&);
102-
103-
size_t Read() const {
104-
count_ += pos_;
105-
pos_ = 0;
106-
len_ = std::fread(buffer_, sizeof(Ch), size_, fp_);
107-
return len_;
66+
void Read() {
67+
if (current_ < bufferLast_)
68+
++current_;
69+
else if (!eof_) {
70+
count_ += readCount_;
71+
readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
72+
bufferLast_ = buffer_ + readCount_ - 1;
73+
current_ = buffer_;
74+
75+
if (readCount_ < bufferSize_) {
76+
buffer_[readCount_] = '\0';
77+
++bufferLast_;
78+
eof_ = true;
79+
}
80+
}
10881
}
10982

11083
std::FILE* fp_;
111-
Ch peekBuffer_[4], *buffer_;
112-
size_t size_;
113-
mutable size_t pos_, len_, count_;
84+
Ch *buffer_;
85+
size_t bufferSize_;
86+
Ch *bufferLast_;
87+
Ch *current_;
88+
size_t readCount_;
89+
size_t count_; //!< Number of characters read
90+
bool eof_;
11491
};
11592

11693
RAPIDJSON_NAMESPACE_END

include/rapidjson/istreamwrapper.h

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include "stream.h"
1919
#include <iosfwd>
20-
#include <cstring>
2120

2221
#ifdef __clang__
2322
RAPIDJSON_DIAG_PUSH
@@ -50,76 +49,70 @@ class BasicIStreamWrapper {
5049
public:
5150
typedef typename StreamType::char_type Ch;
5251

53-
BasicIStreamWrapper(StreamType& stream) : stream_(stream), buffer_(peekBuffer_), size_(sizeof(peekBuffer_) / sizeof(Ch)), pos_(), len_(), count_() {}
54-
55-
BasicIStreamWrapper(StreamType& stream, Ch *buffer, size_t size) : stream_(stream), buffer_(buffer), size_(size), pos_(), len_(), count_() {
56-
RAPIDJSON_ASSERT(buffer_ != 0 && static_cast<std::streamsize>(size_) > 0);
57-
if (RAPIDJSON_UNLIKELY(size_ < sizeof(peekBuffer_) / sizeof(Ch))) {
58-
size_ = sizeof(peekBuffer_) / sizeof(Ch);
59-
buffer_ = peekBuffer_;
60-
}
61-
}
62-
63-
Ch Peek() const {
64-
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read())
65-
return static_cast<Ch>('\0');
66-
return buffer_[pos_];
52+
//! Constructor.
53+
/*!
54+
\param stream stream opened for read.
55+
*/
56+
BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
57+
Read();
6758
}
6859

69-
Ch Take() {
70-
if (RAPIDJSON_UNLIKELY(pos_ == len_) && !Read())
71-
return static_cast<Ch>('\0');
72-
return buffer_[pos_++];
60+
//! Constructor.
61+
/*!
62+
\param stream stream opened for read.
63+
\param buffer user-supplied buffer.
64+
\param bufferSize size of buffer in bytes. Must >=4 bytes.
65+
*/
66+
BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
67+
RAPIDJSON_ASSERT(bufferSize >= 4);
68+
Read();
7369
}
7470

75-
// tellg() may return -1 when failed. So we count by ourself.
76-
size_t Tell() const { return count_ + pos_; }
71+
Ch Peek() const { return *current_; }
72+
Ch Take() { Ch c = *current_; Read(); return c; }
73+
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
7774

7875
// Not implemented
79-
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
8076
void Put(Ch) { RAPIDJSON_ASSERT(false); }
81-
void Flush() { RAPIDJSON_ASSERT(false); }
77+
void Flush() { RAPIDJSON_ASSERT(false); }
78+
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
8279
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
8380

8481
// For encoding detection only.
8582
const Ch* Peek4() const {
86-
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
87-
if (len_ - pos_ < 4) {
88-
if (pos_) {
89-
len_ -= pos_;
90-
std::memmove(buffer_, buffer_ + pos_, len_);
91-
count_ += pos_;
92-
pos_ = 0;
93-
}
94-
if (!stream_.read(buffer_ + len_, static_cast<std::streamsize>(size_ - len_))) {
95-
len_ += static_cast<size_t>(stream_.gcount());
96-
if (len_ < 4)
97-
return 0;
98-
}
99-
else
100-
len_ = size_;
101-
}
102-
return &buffer_[pos_];
83+
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
10384
}
10485

10586
private:
87+
BasicIStreamWrapper();
10688
BasicIStreamWrapper(const BasicIStreamWrapper&);
10789
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
10890

109-
size_t Read() const {
110-
count_ += pos_;
111-
pos_ = 0;
112-
if (!stream_.read(buffer_, static_cast<std::streamsize>(size_)))
113-
len_ = static_cast<size_t>(stream_.gcount());
114-
else
115-
len_ = size_;
116-
return len_;
91+
void Read() {
92+
if (current_ < bufferLast_)
93+
++current_;
94+
else if (!eof_) {
95+
count_ += readCount_;
96+
readCount_ = bufferSize_;
97+
bufferLast_ = buffer_ + readCount_ - 1;
98+
current_ = buffer_;
99+
100+
if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
101+
readCount_ = static_cast<size_t>(stream_.gcount());
102+
*(bufferLast_ = buffer_ + readCount_) = '\0';
103+
eof_ = true;
104+
}
105+
}
117106
}
118107

119-
StreamType& stream_;
108+
StreamType &stream_;
120109
Ch peekBuffer_[4], *buffer_;
121-
size_t size_;
122-
mutable size_t pos_, len_, count_;
110+
size_t bufferSize_;
111+
Ch *bufferLast_;
112+
Ch *current_;
113+
size_t readCount_;
114+
size_t count_; //!< Number of characters read
115+
bool eof_;
123116
};
124117

125118
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;

test/perftest/rapidjsontest.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -454,16 +454,6 @@ TEST_F(RapidJson, FileReadStream) {
454454
}
455455
}
456456

457-
TEST_F(RapidJson, FileReadStream_Unbuffered) {
458-
for (size_t i = 0; i < kTrialCount; i++) {
459-
FILE *fp = fopen(filename_, "rb");
460-
FileReadStream s(fp);
461-
while (s.Take() != '\0')
462-
;
463-
fclose(fp);
464-
}
465-
}
466-
467457
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
468458
for (size_t i = 0; i < kTrialCount; i++) {
469459
FILE *fp = fopen(filename_, "rb");
@@ -476,17 +466,6 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
476466
}
477467
}
478468

479-
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream_Unbuffered)) {
480-
for (size_t i = 0; i < kTrialCount; i++) {
481-
FILE *fp = fopen(filename_, "rb");
482-
FileReadStream s(fp);
483-
BaseReaderHandler<> h;
484-
Reader reader;
485-
reader.Parse(s, h);
486-
fclose(fp);
487-
}
488-
}
489-
490469
TEST_F(RapidJson, IStreamWrapper) {
491470
for (size_t i = 0; i < kTrialCount; i++) {
492471
std::ifstream is(filename_, std::ios::in | std::ios::binary);

0 commit comments

Comments
 (0)