diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index 29ab393..4d42d38 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -69,11 +69,6 @@ private: bool eof_; }; -template<> -struct StreamTraits { - typedef FileReadStream StreamCopyType; // Enable stream copy optimization. -}; - } // namespace rapidjson #endif // RAPIDJSON_FILESTREAM_H_ diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 29fe0ee..6e50293 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -203,12 +203,42 @@ template 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&. + By default, for safety, streams do not use local copy optimization. Stream that can be copied fast should specialize this, like StreamTraits. */ - typedef Stream& StreamCopyType; + enum { copyOptimization = 0 }; +}; + +template +class StreamLocalCopy; + +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : original_(original), s_(original) {} + ~StreamLocalCopy() { original_ = s_; } + Stream* operator->() { return &s_; } + Stream& operator*() { return s_; } + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&); + + Stream& original_; + Stream s_; +}; + +template +class StreamLocalCopy { +public: + StreamLocalCopy(Stream& original) : s_(original) {} + ~StreamLocalCopy() {} + Stream* operator->() { return &s_; } + Stream& operator*() { return s_; } + +private: + StreamLocalCopy& operator=(const StreamLocalCopy&); + + Stream& s_; }; //! Put N copies of a character to a stream. @@ -245,7 +275,7 @@ struct GenericStringStream { template struct StreamTraits > { - typedef GenericStringStream StreamCopyType; // Enable stream copy optimization. + enum { copyOptimization = 1 }; }; typedef GenericStringStream > StringStream; @@ -281,7 +311,7 @@ struct GenericInsituStringStream { template struct StreamTraits > { - typedef GenericInsituStringStream StreamCopyType; // Enable stream copy optimization. + enum { copyOptimization = 1 }; }; typedef GenericInsituStringStream > InsituStringStream; diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 4be8d9c..5add50b 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -135,10 +135,9 @@ struct BaseReaderHandler { */ template void SkipWhitespace(InputStream& is) { - typename StreamTraits::StreamCopyType s = is; // Use a local copy for optimization - while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') - s.Take(); - is = s; + StreamLocalCopy::copyOptimization> s(is); + while (s->Peek() == ' ' || s->Peek() == '\n' || s->Peek() == '\r' || s->Peek() == '\t') + s->Take(); } #ifdef RAPIDJSON_SSE42 @@ -295,6 +294,10 @@ public: size_t GetErrorOffset() const { return errorOffset_; } private: + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader&); + GenericReader& operator=(const GenericReader&); + // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { @@ -406,10 +409,9 @@ private: // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is) { - typename StreamTraits::StreamCopyType s = is; // Use a local copy for optimization unsigned codepoint = 0; for (int i = 0; i < 4; i++) { - Ch c = s.Take(); + Ch c = is.Take(); codepoint <<= 4; codepoint += static_cast(c); if (c >= '0' && c <= '9') @@ -419,11 +421,10 @@ private: else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, s.Tell() - 1); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); return 0; } } - is = s; // Restore is return codepoint; } @@ -447,24 +448,23 @@ private: // Parse string and generate String event. Different code paths for kParseInsituFlag. template void ParseString(InputStream& is, Handler& handler) { - typename StreamTraits::StreamCopyType s = is; // Local copy for optimization + StreamLocalCopy::copyOptimization> s(is); if (parseFlags & kParseInsituFlag) { - Ch *head = s.PutBegin(); - ParseStringToStream(s, s); + Ch *head = s->PutBegin(); + ParseStringToStream(*s, *s); if (HasParseError()) return; - size_t length = s.PutEnd(head) - 1; + size_t length = s->PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false); } else { StackStream stackStream(stack_); - ParseStringToStream(s, stackStream); + ParseStringToStream(*s, stackStream); if (HasParseError()) return; handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true); } - is = s; // Restore is } // Parse string to an output is @@ -527,43 +527,43 @@ private: template void ParseNumber(InputStream& is, Handler& handler) { - typename StreamTraits::StreamCopyType s = is; // Local copy for optimization + StreamLocalCopy::copyOptimization> s(is); // Parse minus bool minus = false; - if (s.Peek() == '-') { + if (s->Peek() == '-') { minus = true; - s.Take(); + s->Take(); } // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i; bool try64bit = false; - if (s.Peek() == '0') { + if (s->Peek() == '0') { i = 0; - s.Take(); + s->Take(); } - else if (s.Peek() >= '1' && s.Peek() <= '9') { - i = static_cast(s.Take() - '0'); + else if (s->Peek() >= '1' && s->Peek() <= '9') { + i = static_cast(s->Take() - '0'); if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (s->Peek() >= '0' && s->Peek() <= '9') { if (i >= 214748364) { // 2^31 = 2147483648 - if (i != 214748364 || s.Peek() > '8') { + if (i != 214748364 || s->Peek() > '8') { try64bit = true; break; } } - i = i * 10 + static_cast(s.Take() - '0'); + i = i * 10 + static_cast(s->Take() - '0'); } else - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (s->Peek() >= '0' && s->Peek() <= '9') { if (i >= 429496729) { // 2^32 - 1 = 4294967295 - if (i != 429496729 || s.Peek() > '5') { + if (i != 429496729 || s->Peek() > '5') { try64bit = true; break; } } - i = i * 10 + static_cast(s.Take() - '0'); + i = i * 10 + static_cast(s->Take() - '0'); } } else @@ -575,22 +575,22 @@ private: if (try64bit) { i64 = i; if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (s->Peek() >= '0' && s->Peek() <= '9') { if (i64 >= UINT64_C(922337203685477580)) // 2^63 = 9223372036854775808 - if (i64 != UINT64_C(922337203685477580) || s.Peek() > '8') { + if (i64 != UINT64_C(922337203685477580) || s->Peek() > '8') { useDouble = true; break; } - i64 = i64 * 10 + static_cast(s.Take() - '0'); + i64 = i64 * 10 + static_cast(s->Take() - '0'); } else - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (s->Peek() >= '0' && s->Peek() <= '9') { if (i64 >= UINT64_C(1844674407370955161)) // 2^64 - 1 = 18446744073709551615 - if (i64 != UINT64_C(1844674407370955161) || s.Peek() > '5') { + if (i64 != UINT64_C(1844674407370955161) || s->Peek() > '5') { useDouble = true; break; } - i64 = i64 * 10 + static_cast(s.Take() - '0'); + i64 = i64 * 10 + static_cast(s->Take() - '0'); } } @@ -598,65 +598,65 @@ private: double d = 0.0; if (useDouble) { d = (double)i64; - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (s->Peek() >= '0' && s->Peek() <= '9') { if (d >= 1E307) RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell()); - d = d * 10 + (s.Take() - '0'); + d = d * 10 + (s->Take() - '0'); } } // Parse frac = decimal-point 1*DIGIT int expFrac = 0; - if (s.Peek() == '.') { + if (s->Peek() == '.') { if (!useDouble) { d = try64bit ? (double)i64 : (double)i; useDouble = true; } - s.Take(); + s->Take(); - if (s.Peek() >= '0' && s.Peek() <= '9') { - d = d * 10 + (s.Take() - '0'); + if (s->Peek() >= '0' && s->Peek() <= '9') { + d = d * 10 + (s->Take() - '0'); --expFrac; } else RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, is.Tell()); - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (s->Peek() >= '0' && s->Peek() <= '9') { if (expFrac > -16) { - d = d * 10 + (s.Peek() - '0'); + d = d * 10 + (s->Peek() - '0'); --expFrac; } - s.Take(); + s->Take(); } } // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; - if (s.Peek() == 'e' || s.Peek() == 'E') { + if (s->Peek() == 'e' || s->Peek() == 'E') { if (!useDouble) { d = try64bit ? (double)i64 : (double)i; useDouble = true; } - s.Take(); + s->Take(); bool expMinus = false; - if (s.Peek() == '+') - s.Take(); - else if (s.Peek() == '-') { - s.Take(); + if (s->Peek() == '+') + s->Take(); + else if (s->Peek() == '-') { + s->Take(); expMinus = true; } - if (s.Peek() >= '0' && s.Peek() <= '9') { - exp = s.Take() - '0'; - while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); + if (s->Peek() >= '0' && s->Peek() <= '9') { + exp = s->Take() - '0'; + while (s->Peek() >= '0' && s->Peek() <= '9') { + exp = exp * 10 + (s->Take() - '0'); if (exp > 308) RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell()); } } else - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, is.Tell()); if (expMinus) exp = -exp; @@ -689,8 +689,6 @@ private: handler.Uint(i); } } - - is = s; // restore is } // Parse any JSON value diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 362cde1..50fadd4 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -623,8 +623,9 @@ public: size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: - // Not support copy constructor. + // Prohibit copy constructor & assignment operator. CustomStringStream(const CustomStringStream&); + CustomStringStream& operator=(const CustomStringStream&); const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. @@ -637,7 +638,7 @@ namespace rapidjson { template struct StreamTraits > { - typedef CustomStringStream StreamCopyType; + enum { copyOptimization = 1 }; }; } // namespace rapdijson