Merge pull request #39 from miloyip/LocalCopyOptimization
Fixes local copy optimization
This commit is contained in:
commit
0c81ed7724
@ -69,11 +69,6 @@ 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_
|
||||||
|
@ -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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
*/
|
*/
|
||||||
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:
|
|||||||
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:
|
|||||||
// 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:
|
|||||||
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:
|
|||||||
// 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:
|
|||||||
|
|
||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
handler.Uint(i);
|
handler.Uint(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is = s; // restore is
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse any JSON value
|
// Parse any JSON value
|
||||||
|
@ -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 {
|
|||||||
|
|
||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user