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 |