Commit d875f16a authored by Milo Yip's avatar Milo Yip

Refactor ParseNumber for two modes (incomplete)

parent b0436911
...@@ -132,7 +132,8 @@ enum ParseFlag { ...@@ -132,7 +132,8 @@ enum ParseFlag {
kParseInsituFlag = 1, //!< In-situ(destructive) parsing. kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
kParseStopWhenDoneFlag = 8 //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
kParseFullPrecisionFlag = 16 //!< Parse number in full precision (but slower).
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
...@@ -644,7 +645,7 @@ private: ...@@ -644,7 +645,7 @@ private:
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream); ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
size_t length = stackStream.Length(); size_t length = stackStream.Length();
if (!handler.String(stackStream.Pop(), length - 1, true)) if (!handler.String(stackStream.Pop(), SizeType(length - 1), true))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
} }
} }
...@@ -710,17 +711,52 @@ private: ...@@ -710,17 +711,52 @@ private:
} }
} }
template<typename InputStream, bool backup>
class NumberStream {
public:
NumberStream(GenericReader& reader, InputStream& is) : reader(reader), is(is) {}
Ch Peek() { return is.Peek(); }
Ch Take() { return is.Take(); }
size_t Tell() { return is.Tell(); }
const char* Pop() { return 0; }
private:
NumberStream& operator=(const NumberStream&);
GenericReader& reader;
InputStream& is;
};
template<typename InputStream>
struct NumberStream<InputStream, true> {
public:
NumberStream(GenericReader& reader, InputStream& is) : reader(reader), is(is), stackStream(reader.stack_) {}
Ch Take() {
stackStream.Put((char)is.Peek());
return is.Take();
}
const char* Pop() {
stackStream.Put('\0');
return stackStream.Pop();
}
private:
GenericReader& reader;
InputStream& is;
StackStream<char> stackStream;
};
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) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
InputStream& s(copy.s); NumberStream<InputStream, parseFlags & kParseFullPrecisionFlag> s(*this, copy.s);
StackStream<char> stackStream(stack_); // Backup string for slow path double conversion.
// Parse minus // Parse minus
bool minus = false; bool minus = false;
if (s.Peek() == '-') { if (s.Peek() == '-') {
minus = true; minus = true;
stackStream.Put(s.Peek());
s.Take(); s.Take();
} }
...@@ -730,11 +766,9 @@ private: ...@@ -730,11 +766,9 @@ private:
bool use64bit = false; bool use64bit = false;
if (s.Peek() == '0') { if (s.Peek() == '0') {
i = 0; i = 0;
stackStream.Put(s.Peek());
s.Take(); s.Take();
} }
else if (s.Peek() >= '1' && s.Peek() <= '9') { else if (s.Peek() >= '1' && s.Peek() <= '9') {
stackStream.Put(s.Peek());
i = static_cast<unsigned>(s.Take() - '0'); i = static_cast<unsigned>(s.Take() - '0');
if (minus) if (minus)
...@@ -746,7 +780,6 @@ private: ...@@ -746,7 +780,6 @@ private:
break; break;
} }
} }
stackStream.Put(s.Peek());
i = i * 10 + static_cast<unsigned>(s.Take() - '0'); i = i * 10 + static_cast<unsigned>(s.Take() - '0');
} }
else else
...@@ -758,7 +791,6 @@ private: ...@@ -758,7 +791,6 @@ private:
break; break;
} }
} }
stackStream.Put(s.Peek());
i = i * 10 + static_cast<unsigned>(s.Take() - '0'); i = i * 10 + static_cast<unsigned>(s.Take() - '0');
} }
} }
...@@ -776,7 +808,6 @@ private: ...@@ -776,7 +808,6 @@ private:
useDouble = true; useDouble = true;
break; break;
} }
stackStream.Put(s.Peek());
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
} }
else else
...@@ -786,7 +817,6 @@ private: ...@@ -786,7 +817,6 @@ private:
useDouble = true; useDouble = true;
break; break;
} }
stackStream.Put(s.Peek());
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
} }
} }
...@@ -794,14 +824,13 @@ private: ...@@ -794,14 +824,13 @@ private:
// Force double for big integer // Force double for big integer
if (useDouble) { if (useDouble) {
while (s.Peek() >= '0' && s.Peek() <= '9') while (s.Peek() >= '0' && s.Peek() <= '9')
stackStream.Put(s.Take()); s.Take();
useStrtod = true; useStrtod = true;
} }
// Parse frac = decimal-point 1*DIGIT // Parse frac = decimal-point 1*DIGIT
int expFrac = 0; int expFrac = 0;
if (s.Peek() == '.') { if (s.Peek() == '.') {
stackStream.Put(s.Peek());
s.Take(); s.Take();
if (!useDouble) { if (!useDouble) {
...@@ -816,7 +845,6 @@ private: ...@@ -816,7 +845,6 @@ private:
break; break;
} }
else { else {
stackStream.Put(s.Peek());
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
--expFrac; --expFrac;
} }
...@@ -826,7 +854,7 @@ private: ...@@ -826,7 +854,7 @@ private:
useDouble = true; useDouble = true;
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
stackStream.Put(s.Take()); s.Take();
--expFrac; --expFrac;
} }
...@@ -838,23 +866,19 @@ private: ...@@ -838,23 +866,19 @@ private:
int exp = 0; int exp = 0;
if (s.Peek() == 'e' || s.Peek() == 'E') { if (s.Peek() == 'e' || s.Peek() == 'E') {
useDouble = true; useDouble = true;
stackStream.Put(s.Peek());
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() == '-') {
stackStream.Put(s.Peek());
s.Take(); s.Take();
expMinus = true; expMinus = true;
} }
if (s.Peek() >= '0' && s.Peek() <= '9') { if (s.Peek() >= '0' && s.Peek() <= '9') {
stackStream.Put(s.Peek());
exp = s.Take() - '0'; exp = s.Take() - '0';
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
stackStream.Put(s.Peek());
exp = exp * 10 + (s.Take() - '0'); exp = exp * 10 + (s.Take() - '0');
if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first.
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
...@@ -871,8 +895,7 @@ private: ...@@ -871,8 +895,7 @@ private:
bool cont = true; bool cont = true;
// Pop stack no matter if it will be used or not. // Pop stack no matter if it will be used or not.
stackStream.Put('\0'); const char* str = s.Pop();
const char* str = stackStream.Pop();
if (useDouble) { if (useDouble) {
int p = exp + expFrac; int p = exp + expFrac;
......
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