Skip to content

Commit b4b0e13

Browse files
authored
Merge pull request Tencent#1424 from ylavic/file_input_streams
Optimize FileReadStream and BasicIStreamWrapper.
2 parents eea3e57 + 8aab3db commit b4b0e13

File tree

2 files changed

+122
-34
lines changed

2 files changed

+122
-34
lines changed

include/rapidjson/istreamwrapper.h

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -48,57 +48,71 @@ template <typename StreamType>
4848
class BasicIStreamWrapper {
4949
public:
5050
typedef typename StreamType::char_type Ch;
51-
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
5251

53-
Ch Peek() const {
54-
typename StreamType::int_type c = stream_.peek();
55-
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : static_cast<Ch>('\0');
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();
5658
}
5759

58-
Ch Take() {
59-
typename StreamType::int_type c = stream_.get();
60-
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
61-
count_++;
62-
return static_cast<Ch>(c);
63-
}
64-
else
65-
return '\0';
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();
6669
}
6770

68-
// tellg() may return -1 when failed. So we count by ourself.
69-
size_t Tell() const { return count_; }
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_); }
7074

71-
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
75+
// Not implemented
7276
void Put(Ch) { RAPIDJSON_ASSERT(false); }
73-
void Flush() { RAPIDJSON_ASSERT(false); }
77+
void Flush() { RAPIDJSON_ASSERT(false); }
78+
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
7479
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
7580

7681
// For encoding detection only.
7782
const Ch* Peek4() const {
78-
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
79-
int i;
80-
bool hasError = false;
81-
for (i = 0; i < 4; ++i) {
82-
typename StreamType::int_type c = stream_.get();
83-
if (c == StreamType::traits_type::eof()) {
84-
hasError = true;
85-
stream_.clear();
86-
break;
87-
}
88-
peekBuffer_[i] = static_cast<Ch>(c);
89-
}
90-
for (--i; i >= 0; --i)
91-
stream_.putback(peekBuffer_[i]);
92-
return !hasError ? peekBuffer_ : 0;
83+
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
9384
}
9485

9586
private:
87+
BasicIStreamWrapper();
9688
BasicIStreamWrapper(const BasicIStreamWrapper&);
9789
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
9890

99-
StreamType& stream_;
100-
size_t count_; //!< Number of characters read. Note:
101-
mutable Ch peekBuffer_[4];
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+
}
106+
}
107+
108+
StreamType &stream_;
109+
Ch peekBuffer_[4], *buffer_;
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_;
102116
};
103117

104118
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;

test/perftest/rapidjsontest.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@
2121
#include "rapidjson/prettywriter.h"
2222
#include "rapidjson/stringbuffer.h"
2323
#include "rapidjson/filereadstream.h"
24+
#include "rapidjson/istreamwrapper.h"
2425
#include "rapidjson/encodedstream.h"
2526
#include "rapidjson/memorystream.h"
2627

28+
#include <fstream>
29+
2730
#ifdef RAPIDJSON_SSE2
2831
#define SIMD_SUFFIX(name) name##_SSE2
2932
#elif defined(RAPIDJSON_SSE42)
@@ -463,6 +466,77 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
463466
}
464467
}
465468

469+
TEST_F(RapidJson, IStreamWrapper) {
470+
for (size_t i = 0; i < kTrialCount; i++) {
471+
std::ifstream is(filename_, std::ios::in | std::ios::binary);
472+
char buffer[65536];
473+
IStreamWrapper isw(is, buffer, sizeof(buffer));
474+
while (isw.Take() != '\0')
475+
;
476+
is.close();
477+
}
478+
}
479+
480+
TEST_F(RapidJson, IStreamWrapper_Unbuffered) {
481+
for (size_t i = 0; i < kTrialCount; i++) {
482+
std::ifstream is(filename_, std::ios::in | std::ios::binary);
483+
IStreamWrapper isw(is);
484+
while (isw.Take() != '\0')
485+
;
486+
is.close();
487+
}
488+
}
489+
490+
TEST_F(RapidJson, IStreamWrapper_Setbuffered) {
491+
for (size_t i = 0; i < kTrialCount; i++) {
492+
std::ifstream is;
493+
char buffer[65536];
494+
is.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
495+
is.open(filename_, std::ios::in | std::ios::binary);
496+
IStreamWrapper isw(is);
497+
while (isw.Take() != '\0')
498+
;
499+
is.close();
500+
}
501+
}
502+
503+
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper)) {
504+
for (size_t i = 0; i < kTrialCount; i++) {
505+
std::ifstream is(filename_, std::ios::in | std::ios::binary);
506+
char buffer[65536];
507+
IStreamWrapper isw(is, buffer, sizeof(buffer));
508+
BaseReaderHandler<> h;
509+
Reader reader;
510+
reader.Parse(isw, h);
511+
is.close();
512+
}
513+
}
514+
515+
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Unbuffered)) {
516+
for (size_t i = 0; i < kTrialCount; i++) {
517+
std::ifstream is(filename_, std::ios::in | std::ios::binary);
518+
IStreamWrapper isw(is);
519+
BaseReaderHandler<> h;
520+
Reader reader;
521+
reader.Parse(isw, h);
522+
is.close();
523+
}
524+
}
525+
526+
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Setbuffered)) {
527+
for (size_t i = 0; i < kTrialCount; i++) {
528+
std::ifstream is;
529+
char buffer[65536];
530+
is.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
531+
is.open(filename_, std::ios::in | std::ios::binary);
532+
IStreamWrapper isw(is);
533+
BaseReaderHandler<> h;
534+
Reader reader;
535+
reader.Parse(isw, h);
536+
is.close();
537+
}
538+
}
539+
466540
TEST_F(RapidJson, StringBuffer) {
467541
StringBuffer sb;
468542
for (int i = 0; i < 32 * 1024 * 1024; i++)

0 commit comments

Comments
 (0)