Skip to content

Commit

Permalink
Refactor ParseNumber for two modes (incomplete)
Browse files Browse the repository at this point in the history
  • Loading branch information
miloyip committed Sep 5, 2014
1 parent b043691 commit d875f16
Showing 1 changed file with 44 additions and 21 deletions.
65 changes: 44 additions & 21 deletions include/rapidjson/reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ enum ParseFlag {
kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
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).
};

///////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -644,7 +645,7 @@ class GenericReader {
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
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());
}
}
Expand Down Expand Up @@ -710,17 +711,52 @@ class GenericReader {
}
}

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>
void ParseNumber(InputStream& is, Handler& handler) {
internal::StreamLocalCopy<InputStream> copy(is);
InputStream& s(copy.s);
StackStream<char> stackStream(stack_); // Backup string for slow path double conversion.
NumberStream<InputStream, parseFlags & kParseFullPrecisionFlag> s(*this, copy.s);

// Parse minus
bool minus = false;
if (s.Peek() == '-') {
minus = true;
stackStream.Put(s.Peek());
s.Take();
}

Expand All @@ -730,11 +766,9 @@ class GenericReader {
bool use64bit = false;
if (s.Peek() == '0') {
i = 0;
stackStream.Put(s.Peek());
s.Take();
}
else if (s.Peek() >= '1' && s.Peek() <= '9') {
stackStream.Put(s.Peek());
i = static_cast<unsigned>(s.Take() - '0');

if (minus)
Expand All @@ -746,7 +780,6 @@ class GenericReader {
break;
}
}
stackStream.Put(s.Peek());
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
}
else
Expand All @@ -758,7 +791,6 @@ class GenericReader {
break;
}
}
stackStream.Put(s.Peek());
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
}
}
Expand All @@ -776,7 +808,6 @@ class GenericReader {
useDouble = true;
break;
}
stackStream.Put(s.Peek());
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
}
else
Expand All @@ -786,22 +817,20 @@ class GenericReader {
useDouble = true;
break;
}
stackStream.Put(s.Peek());
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
}
}

// Force double for big integer
if (useDouble) {
while (s.Peek() >= '0' && s.Peek() <= '9')
stackStream.Put(s.Take());
s.Take();
useStrtod = true;
}

// Parse frac = decimal-point 1*DIGIT
int expFrac = 0;
if (s.Peek() == '.') {
stackStream.Put(s.Peek());
s.Take();

if (!useDouble) {
Expand All @@ -816,7 +845,6 @@ class GenericReader {
break;
}
else {
stackStream.Put(s.Peek());
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
--expFrac;
}
Expand All @@ -826,7 +854,7 @@ class GenericReader {
useDouble = true;

while (s.Peek() >= '0' && s.Peek() <= '9') {
stackStream.Put(s.Take());
s.Take();
--expFrac;
}

Expand All @@ -838,23 +866,19 @@ class GenericReader {
int exp = 0;
if (s.Peek() == 'e' || s.Peek() == 'E') {
useDouble = true;
stackStream.Put(s.Peek());
s.Take();

bool expMinus = false;
if (s.Peek() == '+')
s.Take();
else if (s.Peek() == '-') {
stackStream.Put(s.Peek());
s.Take();
expMinus = true;
}

if (s.Peek() >= '0' && s.Peek() <= '9') {
stackStream.Put(s.Peek());
exp = s.Take() - '0';
while (s.Peek() >= '0' && s.Peek() <= '9') {
stackStream.Put(s.Peek());
exp = exp * 10 + (s.Take() - '0');
if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first.
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
Expand All @@ -871,8 +895,7 @@ class GenericReader {
bool cont = true;

// Pop stack no matter if it will be used or not.
stackStream.Put('\0');
const char* str = stackStream.Pop();
const char* str = s.Pop();

if (useDouble) {
int p = exp + expFrac;
Expand Down

0 comments on commit d875f16

Please sign in to comment.