Commit d8ed6095 authored by Milo Yip's avatar Milo Yip

Merge pull request #32 from miloyip/issue30streamcopy

Make stream local copy optimization as trait option per stream type
parents 6f7d6642 8e76a9dc
...@@ -69,6 +69,11 @@ private: ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 typename 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: ...@@ -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 typename 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: ...@@ -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 typename 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: ...@@ -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 typename 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) { ...@@ -592,4 +592,52 @@ TEST(Reader, SkipWhitespace) {
SkipWhitespace(ss); SkipWhitespace(ss);
EXPECT_EQ(expected[i], ss.Take()); EXPECT_EQ(expected[i], ss.Take());
} }
} }
\ No newline at end of file
// 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_);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment