Add stream copying optimization switch depending stream type.
An unit test is added
This commit is contained in:
parent
6f7d6642ef
commit
bcf7cee788
@ -69,6 +69,11 @@ private:
|
|||||||
bool eof_;
|
bool eof_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StreamTraits<FileReadStream> {
|
||||||
|
typedef FileReadStream StreamCopyType; // Enable stream copy optimization.
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace rapidjson
|
} // namespace rapidjson
|
||||||
|
|
||||||
#endif // RAPIDJSON_FILESTREAM_H_
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
|
@ -193,6 +193,24 @@ concept Stream {
|
|||||||
\endcode
|
\endcode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//! Provides additional information for stream.
|
||||||
|
/*!
|
||||||
|
By using traits pattern, this type provides a default configuration for stream.
|
||||||
|
For custom stream, this type can be specialized for other configuration.
|
||||||
|
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||||
|
*/
|
||||||
|
template<typename Stream>
|
||||||
|
struct StreamTraits {
|
||||||
|
//! Whether to make local copy of stream for optimization during parsing.
|
||||||
|
/*!
|
||||||
|
If it is defined as Stream&, it will not make a local copy.
|
||||||
|
If it is defined as Stream, it will make a local copy for optimization.
|
||||||
|
By default, for safety, streams do not use local copy optimization, i.e. it is defined as Stream&.
|
||||||
|
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||||
|
*/
|
||||||
|
typedef Stream& StreamCopyType;
|
||||||
|
};
|
||||||
|
|
||||||
//! Put N copies of a character to a stream.
|
//! Put N copies of a character to a stream.
|
||||||
template<typename Stream, typename Ch>
|
template<typename Stream, typename Ch>
|
||||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||||
@ -225,6 +243,11 @@ struct GenericStringStream {
|
|||||||
const Ch* head_; //!< Original head of the string.
|
const Ch* head_; //!< Original head of the string.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<GenericStringStream<Encoding>> {
|
||||||
|
typedef GenericStringStream<Encoding> StreamCopyType; // Enable stream copy optimization.
|
||||||
|
};
|
||||||
|
|
||||||
typedef GenericStringStream<UTF8<> > StringStream;
|
typedef GenericStringStream<UTF8<> > StringStream;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -256,6 +279,11 @@ struct GenericInsituStringStream {
|
|||||||
Ch* head_;
|
Ch* head_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<GenericInsituStringStream<Encoding>> {
|
||||||
|
typedef GenericInsituStringStream<Encoding> StreamCopyType; // Enable stream copy optimization.
|
||||||
|
};
|
||||||
|
|
||||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -109,7 +109,7 @@ struct BaseReaderHandler {
|
|||||||
*/
|
*/
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
void SkipWhitespace(InputStream& is) {
|
void SkipWhitespace(InputStream& is) {
|
||||||
InputStream s = is; // Use a local copy for optimization
|
StreamTraits<InputStream>::StreamCopyType s = is; // Use a local copy for optimization
|
||||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||||
s.Take();
|
s.Take();
|
||||||
is = s;
|
is = s;
|
||||||
@ -378,7 +378,7 @@ private:
|
|||||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
unsigned ParseHex4(InputStream& is) {
|
unsigned ParseHex4(InputStream& is) {
|
||||||
InputStream s = is; // Use a local copy for optimization
|
StreamTraits<InputStream>::StreamCopyType s = is; // Use a local copy for optimization
|
||||||
unsigned codepoint = 0;
|
unsigned codepoint = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
Ch c = s.Take();
|
Ch c = s.Take();
|
||||||
@ -419,7 +419,7 @@ private:
|
|||||||
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseString(InputStream& is, Handler& handler) {
|
void ParseString(InputStream& is, Handler& handler) {
|
||||||
InputStream s = is; // Local copy for optimization
|
StreamTraits<InputStream>::StreamCopyType s = is; // Local copy for optimization
|
||||||
if (parseFlags & kParseInsituFlag) {
|
if (parseFlags & kParseInsituFlag) {
|
||||||
Ch *head = s.PutBegin();
|
Ch *head = s.PutBegin();
|
||||||
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
||||||
@ -499,7 +499,7 @@ private:
|
|||||||
|
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseNumber(InputStream& is, Handler& handler) {
|
void ParseNumber(InputStream& is, Handler& handler) {
|
||||||
InputStream s = is; // Local copy for optimization
|
StreamTraits<InputStream>::StreamCopyType s = is; // Local copy for optimization
|
||||||
// Parse minus
|
// Parse minus
|
||||||
bool minus = false;
|
bool minus = false;
|
||||||
if (s.Peek() == '-') {
|
if (s.Peek() == '-') {
|
||||||
|
@ -592,4 +592,52 @@ TEST(Reader, SkipWhitespace) {
|
|||||||
SkipWhitespace(ss);
|
SkipWhitespace(ss);
|
||||||
EXPECT_EQ(expected[i], ss.Take());
|
EXPECT_EQ(expected[i], ss.Take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test implementing a stream without copy stream optimization.
|
||||||
|
// Clone from GenericStringStream except that copy constructor is disabled.
|
||||||
|
template <typename Encoding>
|
||||||
|
class CustomStringStream {
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
CustomStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return *src_; }
|
||||||
|
Ch Take() { return *src_++; }
|
||||||
|
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Not support copy constructor.
|
||||||
|
CustomStringStream(const CustomStringStream&);
|
||||||
|
|
||||||
|
const Ch* src_; //!< Current read position.
|
||||||
|
const Ch* head_; //!< Original head of the string.
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the following code is compiled, it should generate compilation error as predicted.
|
||||||
|
// Because CustomStringStream<> is not copyable via making copy constructor private.
|
||||||
|
#if 0
|
||||||
|
namespace rapidjson {
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<CustomStringStream<Encoding>> {
|
||||||
|
typedef CustomStringStream<Encoding> StreamCopyType;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rapdijson
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST(Reader, CustomStringStream) {
|
||||||
|
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
|
||||||
|
CustomStringStream<UTF8<char>> s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
reader.ParseObject<0>(s, h);
|
||||||
|
EXPECT_EQ(20u, h.step_);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user