Commit 9aec8d6a authored by Milo Yip's avatar Milo Yip

Fixes local copy optimization

The previous optimization #32 has problem that restoration requires
assignment operator.
Change the backup/restore process using a template wrapper class to
select code path.
parent 5852c42b
...@@ -203,12 +203,42 @@ template<typename Stream> ...@@ -203,12 +203,42 @@ template<typename Stream>
struct StreamTraits { struct StreamTraits {
//! Whether to make local copy of stream for optimization during parsing. //! Whether to make local copy of stream for optimization during parsing.
/*! /*!
If it is defined as Stream&, it will not make a local copy. By default, for safety, streams do not use local copy optimization.
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>. Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
*/ */
typedef Stream& StreamCopyType; enum { copyOptimization = 0 };
};
template<typename Stream, bool>
class StreamLocalCopy;
template<typename Stream>
class StreamLocalCopy<Stream, 1> {
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<typename Stream>
class StreamLocalCopy<Stream, 0> {
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. //! Put N copies of a character to a stream.
...@@ -245,7 +275,7 @@ struct GenericStringStream { ...@@ -245,7 +275,7 @@ struct GenericStringStream {
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > { struct StreamTraits<GenericStringStream<Encoding> > {
typedef GenericStringStream<Encoding> StreamCopyType; // Enable stream copy optimization. enum { copyOptimization = 1 };
}; };
typedef GenericStringStream<UTF8<> > StringStream; typedef GenericStringStream<UTF8<> > StringStream;
...@@ -281,7 +311,7 @@ struct GenericInsituStringStream { ...@@ -281,7 +311,7 @@ struct GenericInsituStringStream {
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > { struct StreamTraits<GenericInsituStringStream<Encoding> > {
typedef GenericInsituStringStream<Encoding> StreamCopyType; // Enable stream copy optimization. enum { copyOptimization = 1 };
}; };
typedef GenericInsituStringStream<UTF8<> > InsituStringStream; typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
......
...@@ -135,10 +135,9 @@ struct BaseReaderHandler { ...@@ -135,10 +135,9 @@ struct BaseReaderHandler {
*/ */
template<typename InputStream> template<typename InputStream>
void SkipWhitespace(InputStream& is) { void SkipWhitespace(InputStream& is) {
typename StreamTraits<InputStream>::StreamCopyType s = is; // Use a local copy for optimization StreamLocalCopy<InputStream, StreamTraits<InputStream>::copyOptimization> s(is);
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;
} }
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
...@@ -295,6 +294,10 @@ public: ...@@ -295,6 +294,10 @@ public:
size_t GetErrorOffset() const { return errorOffset_; } size_t GetErrorOffset() const { return errorOffset_; }
private: private:
// Prohibit copy constructor & assignment operator.
GenericReader(const GenericReader&);
GenericReader& operator=(const GenericReader&);
// Parse object: { string : value, ... } // Parse object: { string : value, ... }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseObject(InputStream& is, Handler& handler) { void ParseObject(InputStream& is, Handler& handler) {
...@@ -406,10 +409,9 @@ private: ...@@ -406,10 +409,9 @@ 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) {
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 = is.Take();
codepoint <<= 4; codepoint <<= 4;
codepoint += static_cast<unsigned>(c); codepoint += static_cast<unsigned>(c);
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
...@@ -419,11 +421,10 @@ private: ...@@ -419,11 +421,10 @@ private:
else if (c >= 'a' && c <= 'f') else if (c >= 'a' && c <= 'f')
codepoint -= 'a' - 10; codepoint -= 'a' - 10;
else { else {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, s.Tell() - 1); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);
return 0; return 0;
} }
} }
is = s; // Restore is
return codepoint; return codepoint;
} }
...@@ -447,24 +448,23 @@ private: ...@@ -447,24 +448,23 @@ 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) {
typename StreamTraits<InputStream>::StreamCopyType s = is; // Local copy for optimization StreamLocalCopy<InputStream, StreamTraits<InputStream>::copyOptimization> s(is);
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);
if (HasParseError()) if (HasParseError())
return; return;
size_t length = s.PutEnd(head) - 1; size_t length = s->PutEnd(head) - 1;
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false); handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false);
} }
else { else {
StackStream stackStream(stack_); StackStream stackStream(stack_);
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream); ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(*s, stackStream);
if (HasParseError()) if (HasParseError())
return; return;
handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true); handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true);
} }
is = s; // Restore is
} }
// Parse string to an output is // Parse string to an output is
...@@ -527,43 +527,43 @@ private: ...@@ -527,43 +527,43 @@ 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) {
typename StreamTraits<InputStream>::StreamCopyType s = is; // Local copy for optimization StreamLocalCopy<InputStream, StreamTraits<InputStream>::copyOptimization> s(is);
// Parse minus // Parse minus
bool minus = false; bool minus = false;
if (s.Peek() == '-') { if (s->Peek() == '-') {
minus = true; minus = true;
s.Take(); s->Take();
} }
// Parse int: zero / ( digit1-9 *DIGIT ) // Parse int: zero / ( digit1-9 *DIGIT )
unsigned i; unsigned i;
bool try64bit = false; bool try64bit = false;
if (s.Peek() == '0') { if (s->Peek() == '0') {
i = 0; i = 0;
s.Take(); s->Take();
} }
else if (s.Peek() >= '1' && s.Peek() <= '9') { else if (s->Peek() >= '1' && s->Peek() <= '9') {
i = static_cast<unsigned>(s.Take() - '0'); i = static_cast<unsigned>(s->Take() - '0');
if (minus) 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) { // 2^31 = 2147483648
if (i != 214748364 || s.Peek() > '8') { if (i != 214748364 || s->Peek() > '8') {
try64bit = true; try64bit = true;
break; break;
} }
} }
i = i * 10 + static_cast<unsigned>(s.Take() - '0'); i = i * 10 + static_cast<unsigned>(s->Take() - '0');
} }
else 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) { // 2^32 - 1 = 4294967295
if (i != 429496729 || s.Peek() > '5') { if (i != 429496729 || s->Peek() > '5') {
try64bit = true; try64bit = true;
break; break;
} }
} }
i = i * 10 + static_cast<unsigned>(s.Take() - '0'); i = i * 10 + static_cast<unsigned>(s->Take() - '0');
} }
} }
else else
...@@ -575,22 +575,22 @@ private: ...@@ -575,22 +575,22 @@ private:
if (try64bit) { if (try64bit) {
i64 = i; i64 = i;
if (minus) 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)) // 2^63 = 9223372036854775808
if (i64 != UINT64_C(922337203685477580) || s.Peek() > '8') { if (i64 != UINT64_C(922337203685477580) || s->Peek() > '8') {
useDouble = true; useDouble = true;
break; break;
} }
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s->Take() - '0');
} }
else 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)) // 2^64 - 1 = 18446744073709551615
if (i64 != UINT64_C(1844674407370955161) || s.Peek() > '5') { if (i64 != UINT64_C(1844674407370955161) || s->Peek() > '5') {
useDouble = true; useDouble = true;
break; break;
} }
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s->Take() - '0');
} }
} }
...@@ -598,65 +598,65 @@ private: ...@@ -598,65 +598,65 @@ private:
double d = 0.0; double d = 0.0;
if (useDouble) { if (useDouble) {
d = (double)i64; d = (double)i64;
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s->Peek() >= '0' && s->Peek() <= '9') {
if (d >= 1E307) if (d >= 1E307)
RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell()); RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell());
d = d * 10 + (s.Take() - '0'); d = d * 10 + (s->Take() - '0');
} }
} }
// Parse frac = decimal-point 1*DIGIT // Parse frac = decimal-point 1*DIGIT
int expFrac = 0; int expFrac = 0;
if (s.Peek() == '.') { if (s->Peek() == '.') {
if (!useDouble) { if (!useDouble) {
d = try64bit ? (double)i64 : (double)i; d = try64bit ? (double)i64 : (double)i;
useDouble = true; useDouble = true;
} }
s.Take(); s->Take();
if (s.Peek() >= '0' && s.Peek() <= '9') { if (s->Peek() >= '0' && s->Peek() <= '9') {
d = d * 10 + (s.Take() - '0'); d = d * 10 + (s->Take() - '0');
--expFrac; --expFrac;
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, is.Tell());
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s->Peek() >= '0' && s->Peek() <= '9') {
if (expFrac > -16) { if (expFrac > -16) {
d = d * 10 + (s.Peek() - '0'); d = d * 10 + (s->Peek() - '0');
--expFrac; --expFrac;
} }
s.Take(); s->Take();
} }
} }
// Parse exp = e [ minus / plus ] 1*DIGIT // Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0; int exp = 0;
if (s.Peek() == 'e' || s.Peek() == 'E') { if (s->Peek() == 'e' || s->Peek() == 'E') {
if (!useDouble) { if (!useDouble) {
d = try64bit ? (double)i64 : (double)i; d = try64bit ? (double)i64 : (double)i;
useDouble = true; useDouble = true;
} }
s.Take(); s->Take();
bool expMinus = false; bool expMinus = false;
if (s.Peek() == '+') if (s->Peek() == '+')
s.Take(); s->Take();
else if (s.Peek() == '-') { else if (s->Peek() == '-') {
s.Take(); s->Take();
expMinus = true; expMinus = true;
} }
if (s.Peek() >= '0' && s.Peek() <= '9') { if (s->Peek() >= '0' && s->Peek() <= '9') {
exp = s.Take() - '0'; exp = s->Take() - '0';
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s->Peek() >= '0' && s->Peek() <= '9') {
exp = exp * 10 + (s.Take() - '0'); exp = exp * 10 + (s->Take() - '0');
if (exp > 308) if (exp > 308)
RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell()); RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell());
} }
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, is.Tell());
if (expMinus) if (expMinus)
exp = -exp; exp = -exp;
...@@ -689,8 +689,6 @@ private: ...@@ -689,8 +689,6 @@ private:
handler.Uint(i); handler.Uint(i);
} }
} }
is = s; // restore is
} }
// Parse any JSON value // Parse any JSON value
......
...@@ -623,8 +623,9 @@ public: ...@@ -623,8 +623,9 @@ public:
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private: private:
// Not support copy constructor. // Prohibit copy constructor & assignment operator.
CustomStringStream(const CustomStringStream&); CustomStringStream(const CustomStringStream&);
CustomStringStream& operator=(const CustomStringStream&);
const Ch* src_; //!< Current read position. const Ch* src_; //!< Current read position.
const Ch* head_; //!< Original head of the string. const Ch* head_; //!< Original head of the string.
...@@ -637,7 +638,7 @@ namespace rapidjson { ...@@ -637,7 +638,7 @@ namespace rapidjson {
template <typename Encoding> template <typename Encoding>
struct StreamTraits<CustomStringStream<Encoding> > { struct StreamTraits<CustomStringStream<Encoding> > {
typedef CustomStringStream<Encoding> StreamCopyType; enum { copyOptimization = 1 };
}; };
} // namespace rapdijson } // namespace rapdijson
......
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