"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "include/rapidjson/reader.h" between
rapidjson-1.0.2.tar.gz and rapidjson-1.1.0.tar.gz

About: RapidJSON is a fast JSON parser/generator for C++ with both SAX/DOM style API.

reader.h  (rapidjson-1.0.2):reader.h  (rapidjson-1.1.0)
skipping to change at line 20 skipping to change at line 20
// Unless required by applicable law or agreed to in writing, software distribut ed // Unless required by applicable law or agreed to in writing, software distribut ed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_READER_H_ #ifndef RAPIDJSON_READER_H_
#define RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_
/*! \file reader.h */ /*! \file reader.h */
#include "rapidjson.h" #include "allocators.h"
#include "encodings.h" #include "stream.h"
#include "encodedstream.h"
#include "internal/meta.h" #include "internal/meta.h"
#include "internal/stack.h" #include "internal/stack.h"
#include "internal/strtod.h" #include "internal/strtod.h"
#include <limits>
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
#pragma intrinsic(_BitScanForward) #pragma intrinsic(_BitScanForward)
#endif #endif
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
#include <nmmintrin.h> #include <nmmintrin.h>
#elif defined(RAPIDJSON_SSE2) #elif defined(RAPIDJSON_SSE2)
#include <emmintrin.h> #include <emmintrin.h>
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4702) // unreachable code
#endif #endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(old-style-cast)
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define RAPIDJSON_NOTHING /* deliberately empty */ #define RAPIDJSON_NOTHING /* deliberately empty */
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_MULTILINEMACRO_BEGIN \
if (HasParseError()) { return value; } \ if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
RAPIDJSON_MULTILINEMACRO_END RAPIDJSON_MULTILINEMACRO_END
#endif #endif
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
//!@endcond //!@endcond
/*! \def RAPIDJSON_PARSE_ERROR_NORETURN /*! \def RAPIDJSON_PARSE_ERROR_NORETURN
\ingroup RAPIDJSON_ERRORS \ingroup RAPIDJSON_ERRORS
\brief Macro to indicate a parse error. \brief Macro to indicate a parse error.
\param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
skipping to change at line 143 skipping to change at line 152
//! Combination of parseFlags //! Combination of parseFlags
/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseS tream /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseS tream
*/ */
enum ParseFlag { enum ParseFlag {
kParseNoFlags = 0, //!< No flags are set. kParseNoFlags = 0, //!< No flags are set.
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, par ser 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, par ser will not generate kParseErrorDocumentRootNotSingular error.
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slo wer). kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slo wer).
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**
/) comments.
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as
strings.
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of obj
ects and arrays.
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf
and -Infinity as doubles.
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags . Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags . Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Handler // Handler
/*! \class rapidjson::Handler /*! \class rapidjson::Handler
\brief Concept for receiving events from GenericReader upon parsing. \brief Concept for receiving events from GenericReader upon parsing.
The functions return true if no error occurs. If they return false, The functions return true if no error occurs. If they return false,
the event publisher should terminate the process. the event publisher should terminate the process.
skipping to change at line 164 skipping to change at line 177
concept Handler { concept Handler {
typename Ch; typename Ch;
bool Null(); bool Null();
bool Bool(bool b); bool Bool(bool b);
bool Int(int i); bool Int(int i);
bool Uint(unsigned i); bool Uint(unsigned i);
bool Int64(int64_t i); bool Int64(int64_t i);
bool Uint64(uint64_t i); bool Uint64(uint64_t i);
bool Double(double d); bool Double(double d);
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (u
se length)
bool RawNumber(const Ch* str, SizeType length, bool copy);
bool String(const Ch* str, SizeType length, bool copy); bool String(const Ch* str, SizeType length, bool copy);
bool StartObject(); bool StartObject();
bool Key(const Ch* str, SizeType length, bool copy); bool Key(const Ch* str, SizeType length, bool copy);
bool EndObject(SizeType memberCount); bool EndObject(SizeType memberCount);
bool StartArray(); bool StartArray();
bool EndArray(SizeType elementCount); bool EndArray(SizeType elementCount);
}; };
\endcode \endcode
*/ */
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
skipping to change at line 194 skipping to change at line 209
typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseRea derHandler, Derived>::Type Override; typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseRea derHandler, Derived>::Type Override;
bool Default() { return true; } bool Default() { return true; }
bool Null() { return static_cast<Override&>(*this).Default(); } bool Null() { return static_cast<Override&>(*this).Default(); }
bool Bool(bool) { return static_cast<Override&>(*this).Default(); } bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
bool Int(int) { return static_cast<Override&>(*this).Default(); } bool Int(int) { return static_cast<Override&>(*this).Default(); }
bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); } bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); } bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); } bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
bool Double(double) { return static_cast<Override&>(*this).Default(); } bool Double(double) { return static_cast<Override&>(*this).Default(); }
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (u
se length)
bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<
Override&>(*this).String(str, len, copy); }
bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this ).Default(); } bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this ).Default(); }
bool StartObject() { return static_cast<Override&>(*this).Default(); } bool StartObject() { return static_cast<Override&>(*this).Default(); }
bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Overri de&>(*this).String(str, len, copy); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Overri de&>(*this).String(str, len, copy); }
bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); } bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
bool StartArray() { return static_cast<Override&>(*this).Default(); } bool StartArray() { return static_cast<Override&>(*this).Default(); }
bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); } bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// StreamLocalCopy // StreamLocalCopy
skipping to change at line 251 skipping to change at line 268
//! Skip the JSON white spaces in a stream. //! Skip the JSON white spaces in a stream.
/*! \param is A input stream for skipping white spaces. /*! \param is A input stream for skipping white spaces.
\note This function has SSE2/SSE4.2 specialization. \note This function has SSE2/SSE4.2 specialization.
*/ */
template<typename InputStream> template<typename InputStream>
void SkipWhitespace(InputStream& is) { void SkipWhitespace(InputStream& is) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
InputStream& s(copy.s); InputStream& s(copy.s);
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() = typename InputStream::Ch c;
= '\t') while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
s.Take(); s.Take();
} }
inline const char* SkipWhitespace(const char* p, const char* end) {
while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
return p;
}
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte charac ters at once. //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte charac ters at once.
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
// Fast return for single non-whitespace // Fast return for single non-whitespace
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// 16-byte align to the next boundary // 16-byte align to the next boundary
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<si ze_t>(p) + 15) & ~15); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<si ze_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned) while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// The rest of string using SIMD // The rest of string using SIMD
static const char whitespace[16] = " \n\r\t"; static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]); const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitesp ace[0]));
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128((const __m128i *)p); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SI
| _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); DD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
if (r != 0) { // some of characters is non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset;
_BitScanForward(&offset, r);
return p + offset;
#else
return p + __builtin_ffs(r) - 1;
#endif
}
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
// Fast return for single non-whitespace
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
// The middle of string using SIMD
static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitesp
ace[0]));
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SI
DD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
if (r != 0) { // some of characters is non-whitespace if (r != 0) { // some of characters is non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset; unsigned long offset;
_BitScanForward(&offset, r); _BitScanForward(&offset, r);
return p + offset; return p + offset;
#else #else
return p + __builtin_ffs(r) - 1; return p + __builtin_ffs(r) - 1;
#endif #endif
} }
} }
return SkipWhitespace(p, end);
} }
#elif defined(RAPIDJSON_SSE2) #elif defined(RAPIDJSON_SSE2)
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once . //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once .
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
// Fast return for single non-whitespace // Fast return for single non-whitespace
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// 16-byte align to the next boundary // 16-byte align to the next boundary
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<si ze_t>(p) + 15) & ~15); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<si ze_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned) while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// The rest of string // The rest of string
static const char whitespaces[4][17] = { #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
" ", static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", ('\t') };
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", #undef C16
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); paces[0][0]));
const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); paces[1][0]));
const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
paces[2][0]));
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
paces[3][0]));
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128((const __m128i *)p); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, w0);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
if (r != 0) { // some of characters may be non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset;
_BitScanForward(&offset, r);
return p + offset;
#else
return p + __builtin_ffs(r) - 1;
#endif
}
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
// Fast return for single non-whitespace
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
// The rest of string
#define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16
('\t') };
#undef C16
const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
paces[0][0]));
const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
paces[1][0]));
const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
paces[2][0]));
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whites
paces[3][0]));
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, w0); __m128i x = _mm_cmpeq_epi8(s, w0);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
unsigned short r = (unsigned short)~_mm_movemask_epi8(x); unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
if (r != 0) { // some of characters may be non-whitespace if (r != 0) { // some of characters may be non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset; unsigned long offset;
_BitScanForward(&offset, r); _BitScanForward(&offset, r);
return p + offset; return p + offset;
#else #else
return p + __builtin_ffs(r) - 1; return p + __builtin_ffs(r) - 1;
#endif #endif
} }
} }
return SkipWhitespace(p, end);
} }
#endif // RAPIDJSON_SSE2 #endif // RAPIDJSON_SSE2
#ifdef RAPIDJSON_SIMD #ifdef RAPIDJSON_SIMD
//! Template function specialization for InsituStringStream //! Template function specialization for InsituStringStream
template<> inline void SkipWhitespace(InsituStringStream& is) { template<> inline void SkipWhitespace(InsituStringStream& is) {
is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_)); is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
} }
//! Template function specialization for StringStream //! Template function specialization for StringStream
template<> inline void SkipWhitespace(StringStream& is) { template<> inline void SkipWhitespace(StringStream& is) {
is.src_ = SkipWhitespace_SIMD(is.src_); is.src_ = SkipWhitespace_SIMD(is.src_);
} }
template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>&
is) {
is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
}
#endif // RAPIDJSON_SIMD #endif // RAPIDJSON_SIMD
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericReader // GenericReader
//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocat or. //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocat or.
/*! GenericReader parses JSON text from a stream, and send events synchronously to an /*! GenericReader parses JSON text from a stream, and send events synchronously to an
object implementing Handler concept. object implementing Handler concept.
It needs to allocate a stack for storing a single decoded string during It needs to allocate a stack for storing a single decoded string during
skipping to change at line 401 skipping to change at line 493
*/ */
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
ParseResult Parse(InputStream& is, Handler& handler) { ParseResult Parse(InputStream& is, Handler& handler) {
if (parseFlags & kParseIterativeFlag) if (parseFlags & kParseIterativeFlag)
return IterativeParse<parseFlags>(is, handler); return IterativeParse<parseFlags>(is, handler);
parseResult_.Clear(); parseResult_.Clear();
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (is.Peek() == '\0') { if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
else { else {
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (!(parseFlags & kParseStopWhenDoneFlag)) { if (!(parseFlags & kParseStopWhenDoneFlag)) {
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (is.Peek() != '\0') { if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSin gular, is.Tell()); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSin gular, is.Tell());
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
} }
} }
return parseResult_; return parseResult_;
} }
//! Parse JSON text (with \ref kParseDefaultFlags) //! Parse JSON text (with \ref kParseDefaultFlags)
skipping to change at line 465 skipping to change at line 559
// clear stack on any exit from ParseStream, e.g. due to exception // clear stack on any exit from ParseStream, e.g. due to exception
struct ClearStackOnExit { struct ClearStackOnExit {
explicit ClearStackOnExit(GenericReader& r) : r_(r) {} explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
~ClearStackOnExit() { r_.ClearStack(); } ~ClearStackOnExit() { r_.ClearStack(); }
private: private:
GenericReader& r_; GenericReader& r_;
ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit(const ClearStackOnExit&);
ClearStackOnExit& operator=(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&);
}; };
template<unsigned parseFlags, typename InputStream>
void SkipWhitespaceAndComments(InputStream& is) {
SkipWhitespace(is);
if (parseFlags & kParseCommentsFlag) {
while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
if (Consume(is, '*')) {
while (true) {
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxErr
or, is.Tell());
else if (Consume(is, '*')) {
if (Consume(is, '/'))
break;
}
else
is.Take();
}
}
else if (RAPIDJSON_LIKELY(Consume(is, '/')))
while (is.Peek() != '\0' && is.Take() != '\n');
else
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.T
ell());
SkipWhitespace(is);
}
}
}
// 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) {
RAPIDJSON_ASSERT(is.Peek() == '{'); RAPIDJSON_ASSERT(is.Peek() == '{');
is.Take(); // Skip '{' is.Take(); // Skip '{'
if (!handler.StartObject()) if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == '}') { if (Consume(is, '}')) {
is.Take(); if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
if (!handler.EndObject(0)) // empty object
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
} }
for (SizeType memberCount = 0;;) { for (SizeType memberCount = 0;;) {
if (is.Peek() != '"') if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
ParseString<parseFlags>(is, handler, true); ParseString<parseFlags>(is, handler, true);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Take() != ':') if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
++memberCount; ++memberCount;
switch (is.Take()) { switch (is.Peek()) {
case ',': SkipWhitespace(is); break; case ',':
is.Take();
SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break;
case '}': case '}':
if (!handler.EndObject(memberCount)) is.Take();
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()) ; RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()) ;
return; return;
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurl default:
yBracket, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBrack
et, is.Tell()); break; // This useless break is only for making warning and cove
rage happy
}
if (parseFlags & kParseTrailingCommasFlag) {
if (is.Peek() == '}') {
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell())
;
is.Take();
return;
}
} }
} }
} }
// Parse array: [ value, ... ] // Parse array: [ value, ... ]
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseArray(InputStream& is, Handler& handler) { void ParseArray(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(is.Peek() == '['); RAPIDJSON_ASSERT(is.Peek() == '[');
is.Take(); // Skip '[' is.Take(); // Skip '['
if (!handler.StartArray()) if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == ']') { if (Consume(is, ']')) {
is.Take(); if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
if (!handler.EndArray(0)) // empty array
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
} }
for (SizeType elementCount = 0;;) { for (SizeType elementCount = 0;;) {
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
++elementCount; ++elementCount;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (Consume(is, ',')) {
SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
}
else if (Consume(is, ']')) {
if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return;
}
else
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket,
is.Tell());
switch (is.Take()) { if (parseFlags & kParseTrailingCommasFlag) {
case ',': SkipWhitespace(is); break; if (is.Peek() == ']') {
case ']': if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
if (!handler.EndArray(elementCount))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()) ; RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()) ;
is.Take();
return; return;
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquar eBracket, is.Tell()); }
} }
} }
} }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNull(InputStream& is, Handler& handler) { void ParseNull(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(is.Peek() == 'n'); RAPIDJSON_ASSERT(is.Peek() == 'n');
is.Take(); is.Take();
if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is,
if (!handler.Null()) 'l'))) {
if (RAPIDJSON_UNLIKELY(!handler.Null()))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
} }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseTrue(InputStream& is, Handler& handler) { void ParseTrue(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(is.Peek() == 't'); RAPIDJSON_ASSERT(is.Peek() == 't');
is.Take(); is.Take();
if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is,
if (!handler.Bool(true)) 'e'))) {
if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
} }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseFalse(InputStream& is, Handler& handler) { void ParseFalse(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(is.Peek() == 'f'); RAPIDJSON_ASSERT(is.Peek() == 'f');
is.Take(); is.Take();
if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take( if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is,
) == 'e') { 's') && Consume(is, 'e'))) {
if (!handler.Bool(false)) if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
}
template<typename InputStream>
RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStr
eam::Ch expect) {
if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
is.Take();
return true;
}
else
return false;
} }
// 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, size_t escapeOffset) {
unsigned codepoint = 0; unsigned codepoint = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Ch c = is.Take(); Ch c = is.Peek();
codepoint <<= 4; codepoint <<= 4;
codepoint += static_cast<unsigned>(c); codepoint += static_cast<unsigned>(c);
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
codepoint -= '0'; codepoint -= '0';
else if (c >= 'A' && c <= 'F') else if (c >= 'A' && c <= 'F')
codepoint -= 'A' - 10; codepoint -= 'A' - 10;
else if (c >= 'a' && c <= 'f') else if (c >= 'a' && c <= 'f')
codepoint -= 'a' - 10; codepoint -= 'a' - 10;
else { else {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInv alidHex, is.Tell() - 1); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInv alidHex, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
} }
is.Take();
} }
return codepoint; return codepoint;
} }
template <typename CharType> template <typename CharType>
class StackStream { class StackStream {
public: public:
typedef CharType Ch; typedef CharType Ch;
StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), len gth_(0) {} StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), len gth_(0) {}
RAPIDJSON_FORCEINLINE void Put(Ch c) { RAPIDJSON_FORCEINLINE void Put(Ch c) {
*stack_.template Push<Ch>() = c; *stack_.template Push<Ch>() = c;
++length_; ++length_;
} }
RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
length_ += count;
return stack_.template Push<Ch>(count);
}
size_t Length() const { return length_; } size_t Length() const { return length_; }
Ch* Pop() { Ch* Pop() {
return stack_.template Pop<Ch>(length_); return stack_.template Pop<Ch>(length_);
} }
private: private:
StackStream(const StackStream&); StackStream(const StackStream&);
StackStream& operator=(const StackStream&); StackStream& operator=(const StackStream&);
internal::Stack<StackAllocator>& stack_; internal::Stack<StackAllocator>& stack_;
SizeType length_; SizeType length_;
}; };
// Parse string and generate String event. Different code paths for kParseIn situFlag. // Parse string and generate String event. Different code paths for kParseIn situFlag.
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseString(InputStream& is, Handler& handler, bool isKey = false) { void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
InputStream& s(copy.s); InputStream& s(copy.s);
RAPIDJSON_ASSERT(s.Peek() == '\"');
s.Take(); // Skip '\"'
bool success = false; bool success = false;
if (parseFlags & kParseInsituFlag) { if (parseFlags & kParseInsituFlag) {
typename InputStream::Ch *head = s.PutBegin(); typename InputStream::Ch *head = s.PutBegin();
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s ); ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s );
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
size_t length = s.PutEnd(head) - 1; size_t length = s.PutEnd(head) - 1;
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
const typename TargetEncoding::Ch* const str = (typename TargetEncod ing::Ch*)head; const typename TargetEncoding::Ch* const str = reinterpret_cast<type name TargetEncoding::Ch*>(head);
success = (isKey ? handler.Key(str, SizeType(length), false) : handl er.String(str, SizeType(length), false)); success = (isKey ? handler.Key(str, SizeType(length), false) : handl er.String(str, SizeType(length), false));
} }
else { else {
StackStream<typename TargetEncoding::Ch> stackStream(stack_); StackStream<typename TargetEncoding::Ch> stackStream(stack_);
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, s tackStream); ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, s tackStream);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SizeType length = static_cast<SizeType>(stackStream.Length()) - 1; SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
const typename TargetEncoding::Ch* const str = stackStream.Pop(); const typename TargetEncoding::Ch* const str = stackStream.Pop();
success = (isKey ? handler.Key(str, length, true) : handler.String(s tr, length, true)); success = (isKey ? handler.Key(str, length, true) : handler.String(s tr, length, true));
} }
if (!success) if (RAPIDJSON_UNLIKELY(!success))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
} }
// Parse string to an output is // Parse string to an output is
// This function handles the prefix/suffix double quotes, escaping, and opti onal encoding validation. // This function handles the prefix/suffix double quotes, escaping, and opti onal encoding validation.
template<unsigned parseFlags, typename SEncoding, typename TEncoding, typena me InputStream, typename OutputStream> template<unsigned parseFlags, typename SEncoding, typename TEncoding, typena me InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream & os) { RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream & os) {
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
static const char escape[256] = { static const char escape[256] = {
Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
}; };
#undef Z16 #undef Z16
//!@endcond //!@endcond
RAPIDJSON_ASSERT(is.Peek() == '\"');
is.Take(); // Skip '\"'
for (;;) { for (;;) {
// Scan and copy string before "\\\"" or < 0x20. This is an optional
optimzation.
if (!(parseFlags & kParseValidateEncodingFlag))
ScanCopyUnescapedString(is, os);
Ch c = is.Peek(); Ch c = is.Peek();
if (c == '\\') { // Escape if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
size_t escapeOffset = is.Tell(); // For invalid escaping, rep
ort the inital '\\' as error offset
is.Take(); is.Take();
Ch e = is.Take(); Ch e = is.Peek();
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned c if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(e
har)e]) { scape[static_cast<unsigned char>(e)])) {
os.Put(escape[(unsigned char)e]); is.Take();
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cas
t<unsigned char>(e)]));
} }
else if (e == 'u') { // Unicode else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
unsigned codepoint = ParseHex4(is); is.Take();
unsigned codepoint = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0 xDBFF)) {
// Handle UTF-16 surrogate pair // Handle UTF-16 surrogate pair
if (is.Take() != '\\' || is.Take() != 'u') if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrog , 'u')))
ateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrog
unsigned codepoint2 = ParseHex4(is); ateInvalid, escapeOffset);
unsigned codepoint2 = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrog > 0xDFFF))
ateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrog
ateInvalid, escapeOffset);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
} }
TEncoding::Encode(os, codepoint); TEncoding::Encode(os, codepoint);
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tel l() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escape Offset);
} }
else if (c == '"') { // Closing double quote else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
is.Take(); is.Take();
os.Put('\0'); // null-terminate the string os.Put('\0'); // null-terminate the string
return; return;
} }
else if (c == '\0') else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // R
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tel FC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
l() - 1); if (c == '\0')
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23 RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is
-5B / %x5D-10FFFF .Tell());
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() else
- 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tel
l());
}
else { else {
if (parseFlags & kParseValidateEncodingFlag ? size_t offset = is.Tell();
if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag
?
!Transcoder<SEncoding, TEncoding>::Validate(is, os) : !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
!Transcoder<SEncoding, TEncoding>::Transcode(is, os)) !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.T RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offs
ell()); et);
}
}
}
template<typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, Outp
utStream&) {
// Do nothing for generic version
}
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
// StringStream -> StackStream<char>
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is,
StackStream<char>& os) {
const char* p = is.src_;
// Scan one by one until alignment (unaligned load may cross page bounda
ry and cause crash)
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cas
t<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned)
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\')
|| RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
is.src_ = p;
return;
}
else
os.Put(*p++);
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"
', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\
', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1
9, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dq
uote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bs
lash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&sp
ace[0]));
for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p
));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0
x20 <=> max(s, 0x19) == 0x19
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x))
;
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
SizeType length;
#ifdef _MSC_VER // Find the index of first escaped
unsigned long offset;
_BitScanForward(&offset, r);
length = offset;
#else
length = static_cast<SizeType>(__builtin_ffs(r) - 1);
#endif
char* q = reinterpret_cast<char*>(os.Push(length));
for (size_t i = 0; i < length; i++)
q[i] = p[i];
p += length;
break;
}
_mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
}
is.src_ = p;
}
// InsituStringStream -> InsituStringStream
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream
& is, InsituStringStream& os) {
RAPIDJSON_ASSERT(&is == &os);
(void)os;
if (is.src_ == is.dst_) {
SkipUnescapedString(is);
return;
}
char* p = is.src_;
char *q = is.dst_;
// Scan one by one until alignment (unaligned load may cross page bounda
ry and cause crash)
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cas
t<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned)
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\')
|| RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
is.src_ = p;
is.dst_ = q;
return;
}
else
*q++ = *p++;
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"
', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\
', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dq
uote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bs
lash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&sp
ace[0]));
for (;; p += 16, q += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p
));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0
x20 <=> max(s, 0x19) == 0x19
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x))
;
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
size_t length;
#ifdef _MSC_VER // Find the index of first escaped
unsigned long offset;
_BitScanForward(&offset, r);
length = offset;
#else
length = static_cast<size_t>(__builtin_ffs(r) - 1);
#endif
for (const char* pend = p + length; p != pend; )
*q++ = *p++;
break;
}
_mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
}
is.src_ = p;
is.dst_ = q;
}
// When read/write pointers are the same for insitu stream, just skip unesca
ped characters
static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is
) {
RAPIDJSON_ASSERT(is.src_ == is.dst_);
char* p = is.src_;
// Scan one by one until alignment (unaligned load may cross page bounda
ry and cause crash)
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cas
t<size_t>(p) + 15) & static_cast<size_t>(~15));
for (; p != nextAligned; p++)
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\')
|| RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
is.src_ = is.dst_ = p;
return;
}
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"
', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\
', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19
, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dq
uote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bs
lash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&sp
ace[0]));
for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p
));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0
x20 <=> max(s, 0x19) == 0x19
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x))
;
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
size_t length;
#ifdef _MSC_VER // Find the index of first escaped
unsigned long offset;
_BitScanForward(&offset, r);
length = offset;
#else
length = static_cast<size_t>(__builtin_ffs(r) - 1);
#endif
p += length;
break;
} }
} }
is.src_ = is.dst_ = p;
} }
#endif
template<typename InputStream, bool backup> template<typename InputStream, bool backup, bool pushOnTake>
class NumberStream; class NumberStream;
template<typename InputStream> template<typename InputStream>
class NumberStream<InputStream, false> { class NumberStream<InputStream, false, false> {
public: public:
typedef typename InputStream::Ch Ch;
NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)read er; } NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)read er; }
~NumberStream() {} ~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
RAPIDJSON_FORCEINLINE void Push(char) {}
size_t Tell() { return is.Tell(); } size_t Tell() { return is.Tell(); }
size_t Length() { return 0; } size_t Length() { return 0; }
const char* Pop() { return 0; } const char* Pop() { return 0; }
protected: protected:
NumberStream& operator=(const NumberStream&); NumberStream& operator=(const NumberStream&);
InputStream& is; InputStream& is;
}; };
template<typename InputStream> template<typename InputStream>
class NumberStream<InputStream, true> : public NumberStream<InputStream, fal class NumberStream<InputStream, true, false> : public NumberStream<InputStre
se> { am, false, false> {
typedef NumberStream<InputStream, false> Base; typedef NumberStream<InputStream, false, false> Base;
public: public:
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<Inpu tStream, false>(reader, is), stackStream(reader.stack_) {} NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
~NumberStream() {} ~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch TakePush() { RAPIDJSON_FORCEINLINE Ch TakePush() {
stackStream.Put((char)Base::is.Peek()); stackStream.Put(static_cast<char>(Base::is.Peek()));
return Base::is.Take(); return Base::is.Take();
} }
RAPIDJSON_FORCEINLINE void Push(char c) {
stackStream.Put(c);
}
size_t Length() { return stackStream.Length(); } size_t Length() { return stackStream.Length(); }
const char* Pop() { const char* Pop() {
stackStream.Put('\0'); stackStream.Put('\0');
return stackStream.Pop(); return stackStream.Pop();
} }
private: private:
StackStream<char> stackStream; StackStream<char> stackStream;
}; };
template<typename InputStream>
class NumberStream<InputStream, true, true> : public NumberStream<InputStrea
m, true, false> {
typedef NumberStream<InputStream, true, false> Base;
public:
NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is)
{}
~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
};
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);
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s NumberStream<InputStream,
(*this, copy.s); ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
((parseFlags & kParseInsituFlag) == 0) :
((parseFlags & kParseFullPrecisionFlag) != 0),
(parseFlags & kParseNumbersAsStringsFlag) != 0 &&
(parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
size_t startOffset = s.Tell();
double d = 0.0;
bool useNanOrInf = false;
// Parse minus // Parse minus
bool minus = false; bool minus = Consume(s, '-');
if (s.Peek() == '-') {
minus = true;
s.Take();
}
// Parse int: zero / ( digit1-9 *DIGIT ) // Parse int: zero / ( digit1-9 *DIGIT )
unsigned i = 0; unsigned i = 0;
uint64_t i64 = 0; uint64_t i64 = 0;
bool use64bit = false; bool use64bit = false;
int significandDigit = 0; int significandDigit = 0;
if (s.Peek() == '0') { if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
i = 0; i = 0;
s.TakePush(); s.TakePush();
} }
else if (s.Peek() >= '1' && s.Peek() <= '9') { else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
i = static_cast<unsigned>(s.TakePush() - '0'); i = static_cast<unsigned>(s.TakePush() - '0');
if (minus) if (minus)
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (i >= 214748364) { // 2^31 = 2147483648 if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 21474836
if (i != 214748364 || s.Peek() > '8') { 48
if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8'))
{
i64 = i; i64 = i;
use64bit = true; use64bit = true;
break; break;
} }
} }
i = i * 10 + static_cast<unsigned>(s.TakePush() - '0'); i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++; significandDigit++;
} }
else else
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (i >= 429496729) { // 2^32 - 1 = 4294967295 if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294
if (i != 429496729 || s.Peek() > '5') { 967295
if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5'))
{
i64 = i; i64 = i;
use64bit = true; use64bit = true;
break; break;
} }
} }
i = i * 10 + static_cast<unsigned>(s.TakePush() - '0'); i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++; significandDigit++;
} }
} }
// Parse NaN or Infinity here
else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek(
) == 'I' || s.Peek() == 'N'))) {
useNanOrInf = true;
if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s
, 'N'))) {
d = std::numeric_limits<double>::quiet_NaN();
}
else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Cons
ume(s, 'f'))) {
d = (minus ? -std::numeric_limits<double>::infinity() : std::num
eric_limits<double>::infinity());
if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && C
onsume(s, 'n')
&& Consume(s, 'i') &
& Consume(s, 't') && Consume(s, 'y'))))
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
}
else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
}
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
// Parse 64bit int // Parse 64bit int
bool useDouble = false; bool useDouble = false;
double d = 0.0;
if (use64bit) { if (use64bit) {
if (minus) if (minus)
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCC
2^63 = 9223372036854775808 C, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) | if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCC
| s.Peek() > '8') { CC, 0xCCCCCCCC) || s.Peek() > '8')) {
d = i64; d = static_cast<double>(i64);
useDouble = true; useDouble = true;
break; break;
} }
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++; significandDigit++;
} }
else else
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2 if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999
^64 - 1 = 18446744073709551615 , 0x99999999))) // 2^64 - 1 = 18446744073709551615
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) | if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x199999
| s.Peek() > '5') { 99, 0x99999999) || s.Peek() > '5')) {
d = i64; d = static_cast<double>(i64);
useDouble = true; useDouble = true;
break; break;
} }
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++; significandDigit++;
} }
} }
// Force double for big integer // Force double for big integer
if (useDouble) { if (useDouble) {
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); / 10.0
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
d = d * 10 + (s.TakePush() - '0'); d = d * 10 + (s.TakePush() - '0');
} }
} }
// Parse frac = decimal-point 1*DIGIT // Parse frac = decimal-point 1*DIGIT
int expFrac = 0; int expFrac = 0;
size_t decimalPosition; size_t decimalPosition;
if (s.Peek() == '.') { if (Consume(s, '.')) {
s.Take();
decimalPosition = s.Length(); decimalPosition = s.Length();
if (!(s.Peek() >= '0' && s.Peek() <= '9')) if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
if (!useDouble) { if (!useDouble) {
#if RAPIDJSON_64BIT #if RAPIDJSON_64BIT
// Use i64 to store significand in 64-bit architecture // Use i64 to store significand in 64-bit architecture
if (!use64bit) if (!use64bit)
i64 = i; i64 = i;
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
break; break;
else { else {
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0 '); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0 ');
--expFrac; --expFrac;
if (i64 != 0) if (i64 != 0)
significandDigit++; significandDigit++;
} }
} }
d = (double)i64; d = static_cast<double>(i64);
#else #else
// Use double to store significand in 32-bit architecture // Use double to store significand in 32-bit architecture
d = use64bit ? (double)i64 : (double)i; d = static_cast<double>(use64bit ? i64 : i);
#endif #endif
useDouble = true; useDouble = true;
} }
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (significandDigit < 17) { if (significandDigit < 17) {
d = d * 10.0 + (s.TakePush() - '0'); d = d * 10.0 + (s.TakePush() - '0');
--expFrac; --expFrac;
if (d > 0.0) if (RAPIDJSON_LIKELY(d > 0.0))
significandDigit++; significandDigit++;
} }
else else
s.TakePush(); s.TakePush();
} }
} }
else else
decimalPosition = s.Length(); // decimal position at the end of inte ger. decimalPosition = s.Length(); // decimal position at the end of inte ger.
// 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 (Consume(s, 'e') || Consume(s, 'E')) {
if (!useDouble) { if (!useDouble) {
d = use64bit ? i64 : i; d = static_cast<double>(use64bit ? i64 : i);
useDouble = true; useDouble = true;
} }
s.Take();
bool expMinus = false; bool expMinus = false;
if (s.Peek() == '+') if (Consume(s, '+'))
s.Take(); ;
else if (s.Peek() == '-') { else if (Consume(s, '-'))
s.Take();
expMinus = true; expMinus = true;
}
if (s.Peek() >= '0' && s.Peek() <= '9') { if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
exp = s.Take() - '0'; exp = static_cast<int>(s.Take() - '0');
if (expMinus) { if (expMinus) {
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9'))
exp = exp * 10 + (s.Take() - '0'); {
exp = exp * 10 + static_cast<int>(s.Take() - '0');
if (exp >= 214748364) { // Issue #313: prevent overflow exponent if (exp >= 214748364) { // Issue #313: prevent overflow exponent
while (s.Peek() >= '0' && s.Peek() <= '9') // Consu me the rest of exponent while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek( ) <= '9')) // Consume the rest of exponent
s.Take(); s.Take();
} }
} }
} }
else { // positive exp else { // positive exp
int maxExp = 308 - expFrac; int maxExp = 308 - expFrac;
while (s.Peek() >= '0' && s.Peek() <= '9') { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9'))
exp = exp * 10 + (s.Take() - '0'); {
if (exp > maxExp) exp = exp * 10 + static_cast<int>(s.Take() - '0');
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tel if (RAPIDJSON_UNLIKELY(exp > maxExp))
l()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, start
Offset);
} }
} }
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
if (expMinus) if (expMinus)
exp = -exp; exp = -exp;
} }
// Finish parsing, call event according to the type of number. // Finish parsing, call event according to the type of number.
bool cont = true; bool cont = true;
size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be use
d or not.
if (useDouble) { if (parseFlags & kParseNumbersAsStringsFlag) {
int p = exp + expFrac; if (parseFlags & kParseInsituFlag) {
if (parseFlags & kParseFullPrecisionFlag) s.Pop(); // Pop stack no matter if it will be used or not.
d = internal::StrtodFullPrecision(d, p, decimal, length, decimal typename InputStream::Ch* head = is.PutBegin();
Position, exp); const size_t length = s.Tell() - startOffset;
else RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
d = internal::StrtodNormalPrecision(d, p); // unable to insert the \0 character here, it will erase the com
ma after this number
cont = handler.Double(minus ? -d : d); const typename TargetEncoding::Ch* const str = reinterpret_cast<
} typename TargetEncoding::Ch*>(head);
else { cont = handler.RawNumber(str, SizeType(length), false);
if (use64bit) {
if (minus)
cont = handler.Int64(-(int64_t)i64);
else
cont = handler.Uint64(i64);
} }
else { else {
if (minus) SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
cont = handler.Int(-(int)i); StringStream srcStream(s.Pop());
else StackStream<typename TargetEncoding::Ch> dstStream(stack_);
cont = handler.Uint(i); while (numCharsToCopy--) {
Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dst
Stream);
}
dstStream.Put('\0');
const typename TargetEncoding::Ch* str = dstStream.Pop();
const SizeType length = static_cast<SizeType>(dstStream.Length()
) - 1;
cont = handler.RawNumber(str, SizeType(length), true);
} }
} }
if (!cont) else {
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be
used or not.
if (useDouble) {
int p = exp + expFrac;
if (parseFlags & kParseFullPrecisionFlag)
d = internal::StrtodFullPrecision(d, p, decimal, length, deci
malPosition, exp);
else
d = internal::StrtodNormalPrecision(d, p);
cont = handler.Double(minus ? -d : d);
}
else if (useNanOrInf) {
cont = handler.Double(d);
}
else {
if (use64bit) {
if (minus)
cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
else
cont = handler.Uint64(i64);
}
else {
if (minus)
cont = handler.Int(static_cast<int32_t>(~i + 1));
else
cont = handler.Uint(i);
}
}
}
if (RAPIDJSON_UNLIKELY(!cont))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
} }
// Parse any JSON value // Parse any JSON value
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseValue(InputStream& is, Handler& handler) { void ParseValue(InputStream& is, Handler& handler) {
switch (is.Peek()) { switch (is.Peek()) {
case 'n': ParseNull <parseFlags>(is, handler); break; case 'n': ParseNull <parseFlags>(is, handler); break;
case 't': ParseTrue <parseFlags>(is, handler); break; case 't': ParseTrue <parseFlags>(is, handler); break;
case 'f': ParseFalse <parseFlags>(is, handler); break; case 'f': ParseFalse <parseFlags>(is, handler); break;
case '"': ParseString<parseFlags>(is, handler); break; case '"': ParseString<parseFlags>(is, handler); break;
case '{': ParseObject<parseFlags>(is, handler); break; case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray <parseFlags>(is, handler); break; case '[': ParseArray <parseFlags>(is, handler); break;
default : ParseNumber<parseFlags>(is, handler); default :
ParseNumber<parseFlags>(is, handler);
break;
} }
} }
// Iterative Parsing // Iterative Parsing
// States // States
enum IterativeParsingState { enum IterativeParsingState {
IterativeParsingStartState = 0, IterativeParsingStartState = 0,
IterativeParsingFinishState, IterativeParsingFinishState,
IterativeParsingErrorState, IterativeParsingErrorState,
skipping to change at line 1022 skipping to change at line 1430
IterativeParsingMemberDelimiterState, IterativeParsingMemberDelimiterState,
IterativeParsingObjectFinishState, IterativeParsingObjectFinishState,
// Array states // Array states
IterativeParsingArrayInitialState, IterativeParsingArrayInitialState,
IterativeParsingElementState, IterativeParsingElementState,
IterativeParsingElementDelimiterState, IterativeParsingElementDelimiterState,
IterativeParsingArrayFinishState, IterativeParsingArrayFinishState,
// Single value state // Single value state
IterativeParsingValueState, IterativeParsingValueState
cIterativeParsingStateCount
}; };
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
// Tokens // Tokens
enum Token { enum Token {
LeftBracketToken = 0, LeftBracketToken = 0,
RightBracketToken, RightBracketToken,
LeftCurlyBracketToken, LeftCurlyBracketToken,
RightCurlyBracketToken, RightCurlyBracketToken,
CommaToken, CommaToken,
ColonToken, ColonToken,
skipping to change at line 1068 skipping to change at line 1476
N16, // 40~4F N16, // 40~4F
N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketTo ken, N, N, // 50~5F N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketTo ken, N, N, // 50~5F
N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, R ightCurlyBracketToken, N, N, // 70~7F N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, R ightCurlyBracketToken, N, N, // 70~7F
N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
}; };
#undef N #undef N
#undef N16 #undef N16
//!@endcond //!@endcond
if (sizeof(Ch) == 1 || unsigned(c) < 256) if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
return (Token)tokenMap[(unsigned char)c]; return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
else else
return NumberToken; return NumberToken;
} }
RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState st ate, Token token) { RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState st ate, Token token) {
// current state x one lookahead token -> new state // current state x one lookahead token -> new state
static const char G[cIterativeParsingStateCount][kTokenCount] = { static const char G[cIterativeParsingStateCount][kTokenCount] = {
// Start // Start
{ {
IterativeParsingArrayInitialState, // Left bracket IterativeParsingArrayInitialState, // Left bracket
skipping to change at line 1164 skipping to change at line 1572
IterativeParsingErrorState, // False IterativeParsingErrorState, // False
IterativeParsingErrorState, // True IterativeParsingErrorState, // True
IterativeParsingErrorState, // Null IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number IterativeParsingErrorState // Number
}, },
// MemberDelimiter // MemberDelimiter
{ {
IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Left bracket
IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Right bracket
IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Left curly bracket
IterativeParsingErrorState, // Right curly bracket IterativeParsingObjectFinishState, // Right curly bracket
IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Comma
IterativeParsingErrorState, // Colon IterativeParsingErrorState, // Colon
IterativeParsingMemberKeyState, // String IterativeParsingMemberKeyState, // String
IterativeParsingErrorState, // False IterativeParsingErrorState, // False
IterativeParsingErrorState, // True IterativeParsingErrorState, // True
IterativeParsingErrorState, // Null IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number IterativeParsingErrorState // Number
}, },
// ObjectFinish(sink state) // ObjectFinish(sink state)
{ {
skipping to change at line 1210 skipping to change at line 1618
IterativeParsingErrorState, // Colon IterativeParsingErrorState, // Colon
IterativeParsingErrorState, // String IterativeParsingErrorState, // String
IterativeParsingErrorState, // False IterativeParsingErrorState, // False
IterativeParsingErrorState, // True IterativeParsingErrorState, // True
IterativeParsingErrorState, // Null IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number IterativeParsingErrorState // Number
}, },
// ElementDelimiter // ElementDelimiter
{ {
IterativeParsingArrayInitialState, // Left bracket(push Ele ment state) IterativeParsingArrayInitialState, // Left bracket(push Ele ment state)
IterativeParsingErrorState, // Right bracket IterativeParsingArrayFinishState, // Right bracket
IterativeParsingObjectInitialState, // Left curly bracket(pu sh Element state) IterativeParsingObjectInitialState, // Left curly bracket(pu sh Element state)
IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Right curly bracket
IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Comma
IterativeParsingErrorState, // Colon IterativeParsingErrorState, // Colon
IterativeParsingElementState, // String IterativeParsingElementState, // String
IterativeParsingElementState, // False IterativeParsingElementState, // False
IterativeParsingElementState, // True IterativeParsingElementState, // True
IterativeParsingElementState, // Null IterativeParsingElementState, // Null
IterativeParsingElementState // Number IterativeParsingElementState // Number
}, },
skipping to change at line 1235 skipping to change at line 1643
IterativeParsingErrorState IterativeParsingErrorState
}, },
// Single Value (sink state) // Single Value (sink state)
{ {
IterativeParsingErrorState, IterativeParsingErrorState, Iterativ eParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, Iterativ eParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
IterativeParsingErrorState, IterativeParsingErrorState, Iterativ eParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, Iterativ eParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
IterativeParsingErrorState IterativeParsingErrorState
} }
}; // End of G }; // End of G
return (IterativeParsingState)G[state][token]; return static_cast<IterativeParsingState>(G[state][token]);
} }
// Make an advance in the token stream and state based on the candidate dest ination state which was returned by Transit(). // Make an advance in the token stream and state based on the candidate dest ination state which was returned by Transit().
// May return a new state on state pop. // May return a new state on state pop.
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState sr c, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState sr c, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
(void)token; (void)token;
switch (dst) { switch (dst) {
case IterativeParsingErrorState: case IterativeParsingErrorState:
skipping to change at line 1312 skipping to change at line 1720
case IterativeParsingMemberDelimiterState: case IterativeParsingMemberDelimiterState:
case IterativeParsingElementDelimiterState: case IterativeParsingElementDelimiterState:
is.Take(); is.Take();
// Update member/element count. // Update member/element count.
*stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1; *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
return dst; return dst;
case IterativeParsingObjectFinishState: case IterativeParsingObjectFinishState:
{ {
// Transit from delimiter is only allowed when trailing commas are e
nabled
if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativePars
ingMemberDelimiterState) {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tel
l());
return IterativeParsingErrorState;
}
// Get member count. // Get member count.
SizeType c = *stack_.template Pop<SizeType>(1); SizeType c = *stack_.template Pop<SizeType>(1);
// If the object is not empty, count the last member. // If the object is not empty, count the last member.
if (src == IterativeParsingMemberValueState) if (src == IterativeParsingMemberValueState)
++c; ++c;
// Restore the state. // Restore the state.
IterativeParsingState n = static_cast<IterativeParsingState>(*stack_ .template Pop<SizeType>(1)); IterativeParsingState n = static_cast<IterativeParsingState>(*stack_ .template Pop<SizeType>(1));
// Transit to Finish state if this is the topmost scope. // Transit to Finish state if this is the topmost scope.
if (n == IterativeParsingStartState) if (n == IterativeParsingStartState)
n = IterativeParsingFinishState; n = IterativeParsingFinishState;
skipping to change at line 1337 skipping to change at line 1750
return IterativeParsingErrorState; return IterativeParsingErrorState;
} }
else { else {
is.Take(); is.Take();
return n; return n;
} }
} }
case IterativeParsingArrayFinishState: case IterativeParsingArrayFinishState:
{ {
// Transit from delimiter is only allowed when trailing commas are e
nabled
if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativePars
ingElementDelimiterState) {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell(
));
return IterativeParsingErrorState;
}
// Get element count. // Get element count.
SizeType c = *stack_.template Pop<SizeType>(1); SizeType c = *stack_.template Pop<SizeType>(1);
// If the array is not empty, count the last element. // If the array is not empty, count the last element.
if (src == IterativeParsingElementState) if (src == IterativeParsingElementState)
++c; ++c;
// Restore the state. // Restore the state.
IterativeParsingState n = static_cast<IterativeParsingState>(*stack_ .template Pop<SizeType>(1)); IterativeParsingState n = static_cast<IterativeParsingState>(*stack_ .template Pop<SizeType>(1));
// Transit to Finish state if this is the topmost scope. // Transit to Finish state if this is the topmost scope.
if (n == IterativeParsingStartState) if (n == IterativeParsingStartState)
n = IterativeParsingFinishState; n = IterativeParsingFinishState;
skipping to change at line 1390 skipping to change at line 1808
} }
template <typename InputStream> template <typename InputStream>
void HandleError(IterativeParsingState src, InputStream& is) { void HandleError(IterativeParsingState src, InputStream& is) {
if (HasParseError()) { if (HasParseError()) {
// Error flag has been set. // Error flag has been set.
return; return;
} }
switch (src) { switch (src) {
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParse
ErrorDocumentEmpty, is.Tell()); ErrorDocumentEmpty, is.Tell()); return;
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParse
ErrorDocumentRootNotSingular, is.Tell()); ErrorDocumentRootNotSingular, is.Tell()); return;
case IterativeParsingObjectInitialState: case IterativeParsingObjectInitialState:
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParse
ErrorObjectMissName, is.Tell()); ErrorObjectMissName, is.Tell()); return;
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParse
ErrorObjectMissColon, is.Tell()); ErrorObjectMissColon, is.Tell()); return;
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParse
ErrorObjectMissCommaOrCurlyBracket, is.Tell()); ErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingKeyValueDelimiterState:
ErrorArrayMissCommaOrSquareBracket, is.Tell()); case IterativeParsingArrayInitialState:
default: RAPIDJSON_PARSE_ERROR(kParse case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParse
ErrorUnspecificSyntaxError, is.Tell()); ErrorValueInvalid, is.Tell()); return;
default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSO
N_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
} }
} }
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
ParseResult IterativeParse(InputStream& is, Handler& handler) { ParseResult IterativeParse(InputStream& is, Handler& handler) {
parseResult_.Clear(); parseResult_.Clear();
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
IterativeParsingState state = IterativeParsingStartState; IterativeParsingState state = IterativeParsingStartState;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
while (is.Peek() != '\0') { while (is.Peek() != '\0') {
Token t = Tokenize(is.Peek()); Token t = Tokenize(is.Peek());
IterativeParsingState n = Predict(state, t); IterativeParsingState n = Predict(state, t);
IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handl er); IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handl er);
if (d == IterativeParsingErrorState) { if (d == IterativeParsingErrorState) {
HandleError(state, is); HandleError(state, is);
break; break;
} }
state = d; state = d;
// Do not further consume streams if a root JSON has been parsed. // Do not further consume streams if a root JSON has been parsed.
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsi ngFinishState) if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsi ngFinishState)
break; break;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
// Handle the end of file. // Handle the end of file.
if (state != IterativeParsingFinishState) if (state != IterativeParsingFinishState)
HandleError(state, is); HandleError(state, is);
return parseResult_; return parseResult_;
} }
static const size_t kDefaultStackCapacity = 256; //!< Default stack capac ity in bytes for storing a single decoded string. static const size_t kDefaultStackCapacity = 256; //!< Default stack capac ity in bytes for storing a single decoded string.
internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded st ring temporarily during non-destructive parsing. internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded st ring temporarily during non-destructive parsing.
ParseResult parseResult_; ParseResult parseResult_;
}; // class GenericReader }; // class GenericReader
//! Reader with UTF8 encoding and default allocator. //! Reader with UTF8 encoding and default allocator.
typedef GenericReader<UTF8<>, UTF8<> > Reader; typedef GenericReader<UTF8<>, UTF8<> > Reader;
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#endif // RAPIDJSON_READER_H_ #endif // RAPIDJSON_READER_H_
 End of changes. 126 change blocks. 
213 lines changed or deleted 737 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)