2016-09-17 09:35:49 +02:00
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// 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
// specific language governing permissions and limitations under the License.
# ifndef RAPIDJSON_READER_H_
# define RAPIDJSON_READER_H_
/*! \file reader.h */
# include "allocators.h"
# include "stream.h"
# include "encodedstream.h"
# include "internal/meta.h"
# include "internal/stack.h"
# include "internal/strtod.h"
# include <limits>
# if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
# include <intrin.h>
# pragma intrinsic(_BitScanForward)
# endif
# ifdef RAPIDJSON_SSE42
# include <nmmintrin.h>
# elif defined(RAPIDJSON_SSE2)
# include <emmintrin.h>
# endif
# ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF ( 4127 ) // conditional expression is constant
RAPIDJSON_DIAG_OFF ( 4702 ) // unreachable code
# endif
# ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF ( old - style - cast )
RAPIDJSON_DIAG_OFF ( padded )
RAPIDJSON_DIAG_OFF ( switch - enum )
# endif
# ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF ( effc + + )
# endif
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
# define RAPIDJSON_NOTHING /* deliberately empty */
# ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
# define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
RAPIDJSON_MULTILINEMACRO_BEGIN \
if ( RAPIDJSON_UNLIKELY ( HasParseError ( ) ) ) { return value ; } \
RAPIDJSON_MULTILINEMACRO_END
# endif
# define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( RAPIDJSON_NOTHING )
//!@endcond
/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
\ ingroup RAPIDJSON_ERRORS
\ brief Macro to indicate a parse error .
\ param parseErrorCode \ ref rapidjson : : ParseErrorCode of the error
\ param offset position of the error in JSON input ( \ c size_t )
This macros can be used as a customization point for the internal
error handling mechanism of RapidJSON .
A common usage model is to throw an exception instead of requiring the
caller to explicitly check the \ ref rapidjson : : GenericReader : : Parse ' s
return value :
\ code
# define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
throw ParseException ( parseErrorCode , # parseErrorCode , offset )
# include <stdexcept> // std::runtime_error
# include "rapidjson/error/error.h" // rapidjson::ParseResult
struct ParseException : std : : runtime_error , rapidjson : : ParseResult {
ParseException ( rapidjson : : ParseErrorCode code , const char * msg , size_t offset )
: std : : runtime_error ( msg ) , ParseResult ( code , offset ) { }
} ;
# include "rapidjson/reader.h"
\ endcode
\ see RAPIDJSON_PARSE_ERROR , rapidjson : : GenericReader : : Parse
*/
# ifndef RAPIDJSON_PARSE_ERROR_NORETURN
# define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
RAPIDJSON_MULTILINEMACRO_BEGIN \
RAPIDJSON_ASSERT ( ! HasParseError ( ) ) ; /* Error can only be assigned once */ \
SetParseError ( parseErrorCode , offset ) ; \
RAPIDJSON_MULTILINEMACRO_END
# endif
/*! \def RAPIDJSON_PARSE_ERROR
\ ingroup RAPIDJSON_ERRORS
\ brief ( Internal ) macro to indicate and handle a parse error .
\ param parseErrorCode \ ref rapidjson : : ParseErrorCode of the error
\ param offset position of the error in JSON input ( \ c size_t )
Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing .
\ see RAPIDJSON_PARSE_ERROR_NORETURN
\ hideinitializer
*/
# ifndef RAPIDJSON_PARSE_ERROR
# define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
RAPIDJSON_MULTILINEMACRO_BEGIN \
RAPIDJSON_PARSE_ERROR_NORETURN ( parseErrorCode , offset ) ; \
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ; \
RAPIDJSON_MULTILINEMACRO_END
# endif
# include "error/error.h" // ParseErrorCode, ParseResult
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// ParseFlag
/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
\ ingroup RAPIDJSON_CONFIG
\ brief User - defined kParseDefaultFlags definition .
User can define this as any \ c ParseFlag combinations .
*/
# ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
# define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
# endif
//! Combination of parseFlags
/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
*/
enum ParseFlag {
kParseNoFlags = 0 , //!< No flags are set.
kParseInsituFlag = 1 , //!< In-situ(destructive) parsing.
kParseValidateEncodingFlag = 2 , //!< Validate encoding of JSON strings.
kParseIterativeFlag = 4 , //!< Iterative(constant complexity in terms of function call stack size) parsing.
kParseStopWhenDoneFlag = 8 , //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
kParseFullPrecisionFlag = 16 , //!< Parse number in full precision (but slower).
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 objects 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
} ;
///////////////////////////////////////////////////////////////////////////////
// Handler
/*! \class rapidjson::Handler
\ brief Concept for receiving events from GenericReader upon parsing .
The functions return true if no error occurs . If they return false ,
the event publisher should terminate the process .
\ code
concept Handler {
typename Ch ;
bool Null ( ) ;
bool Bool ( bool b ) ;
bool Int ( int i ) ;
bool Uint ( unsigned i ) ;
bool Int64 ( int64_t i ) ;
bool Uint64 ( uint64_t i ) ;
bool Double ( double d ) ;
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
bool RawNumber ( const Ch * str , SizeType length , bool copy ) ;
bool String ( const Ch * str , SizeType length , bool copy ) ;
bool StartObject ( ) ;
bool Key ( const Ch * str , SizeType length , bool copy ) ;
bool EndObject ( SizeType memberCount ) ;
bool StartArray ( ) ;
bool EndArray ( SizeType elementCount ) ;
} ;
\ endcode
*/
///////////////////////////////////////////////////////////////////////////////
// BaseReaderHandler
//! Default implementation of Handler.
/*! This can be used as base class of any reader handler.
\ note implements Handler concept
*/
template < typename Encoding = UTF8 < > , typename Derived = void >
struct BaseReaderHandler {
typedef typename Encoding : : Ch Ch ;
typedef typename internal : : SelectIf < internal : : IsSame < Derived , void > , BaseReaderHandler , Derived > : : Type Override ;
bool Default ( ) { return true ; }
bool Null ( ) { 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 Uint ( unsigned ) { 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 Double ( double ) { return static_cast < Override & > ( * this ) . Default ( ) ; }
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use 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 StartObject ( ) { return static_cast < Override & > ( * this ) . Default ( ) ; }
bool Key ( const Ch * str , SizeType len , bool copy ) { return static_cast < Override & > ( * this ) . String ( str , len , copy ) ; }
bool EndObject ( SizeType ) { return static_cast < Override & > ( * this ) . Default ( ) ; }
bool StartArray ( ) { return static_cast < Override & > ( * this ) . Default ( ) ; }
bool EndArray ( SizeType ) { return static_cast < Override & > ( * this ) . Default ( ) ; }
} ;
///////////////////////////////////////////////////////////////////////////////
// StreamLocalCopy
namespace internal {
template < typename Stream , int = StreamTraits < Stream > : : copyOptimization >
class StreamLocalCopy ;
//! Do copy optimization.
template < typename Stream >
class StreamLocalCopy < Stream , 1 > {
public :
StreamLocalCopy ( Stream & original ) : s ( original ) , original_ ( original ) { }
~ StreamLocalCopy ( ) { original_ = s ; }
Stream s ;
private :
StreamLocalCopy & operator = ( const StreamLocalCopy & ) /* = delete */ ;
Stream & original_ ;
} ;
//! Keep reference.
template < typename Stream >
class StreamLocalCopy < Stream , 0 > {
public :
StreamLocalCopy ( Stream & original ) : s ( original ) { }
Stream & s ;
private :
StreamLocalCopy & operator = ( const StreamLocalCopy & ) /* = delete */ ;
} ;
} // namespace internal
///////////////////////////////////////////////////////////////////////////////
// SkipWhitespace
//! Skip the JSON white spaces in a stream.
/*! \param is A input stream for skipping white spaces.
\ note This function has SSE2 / SSE4 .2 specialization .
*/
template < typename InputStream >
void SkipWhitespace ( InputStream & is ) {
internal : : StreamLocalCopy < InputStream > copy ( is ) ;
InputStream & s ( copy . s ) ;
typename InputStream : : Ch c ;
while ( ( c = s . Peek ( ) ) = = ' ' | | c = = ' \n ' | | c = = ' \r ' | | c = = ' \t ' )
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
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char * SkipWhitespace_SIMD ( const char * p ) {
// Fast return for single non-whitespace
if ( * p = = ' ' | | * p = = ' \n ' | | * p = = ' \r ' | | * p = = ' \t ' )
+ + p ;
else
return p ;
// 16-byte align to the next boundary
const char * nextAligned = reinterpret_cast < const char * > ( ( reinterpret_cast < size_t > ( p ) + 15 ) & static_cast < size_t > ( ~ 15 ) ) ;
while ( p ! = nextAligned )
if ( * p = = ' ' | | * p = = ' \n ' | | * p = = ' \r ' | | * p = = ' \t ' )
+ + p ;
else
return p ;
// The rest of string using SIMD
static const char whitespace [ 16 ] = " \n \r \t " ;
const __m128i w = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespace [ 0 ] ) ) ;
for ( ; ; p + = 16 ) {
const __m128i s = _mm_load_si128 ( reinterpret_cast < const __m128i * > ( p ) ) ;
const int r = _mm_cvtsi128_si32 ( _mm_cmpistrm ( w , s , _SIDD_UBYTE_OPS | _SIDD_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 * > ( & whitespace [ 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 | _SIDD_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
}
}
return SkipWhitespace ( p , end ) ;
}
# elif defined(RAPIDJSON_SSE2)
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
inline const char * SkipWhitespace_SIMD ( const char * p ) {
// Fast return for single non-whitespace
if ( * p = = ' ' | | * p = = ' \n ' | | * p = = ' \r ' | | * p = = ' \t ' )
+ + p ;
else
return p ;
// 16-byte align to the next boundary
const char * nextAligned = reinterpret_cast < const char * > ( ( reinterpret_cast < size_t > ( p ) + 15 ) & static_cast < size_t > ( ~ 15 ) ) ;
while ( p ! = nextAligned )
if ( * 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 * > ( & whitespaces [ 0 ] [ 0 ] ) ) ;
const __m128i w1 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 1 ] [ 0 ] ) ) ;
const __m128i w2 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 2 ] [ 0 ] ) ) ;
const __m128i w3 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 3 ] [ 0 ] ) ) ;
for ( ; ; p + = 16 ) {
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 * > ( & whitespaces [ 0 ] [ 0 ] ) ) ;
const __m128i w1 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 1 ] [ 0 ] ) ) ;
const __m128i w2 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 2 ] [ 0 ] ) ) ;
const __m128i w3 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 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 ) ;
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
}
}
return SkipWhitespace ( p , end ) ;
}
# endif // RAPIDJSON_SSE2
# ifdef RAPIDJSON_SIMD
//! Template function specialization for InsituStringStream
template < > inline void SkipWhitespace ( InsituStringStream & is ) {
is . src_ = const_cast < char * > ( SkipWhitespace_SIMD ( is . src_ ) ) ;
}
//! Template function specialization for StringStream
template < > inline void SkipWhitespace ( StringStream & is ) {
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
///////////////////////////////////////////////////////////////////////////////
// GenericReader
//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
/*! GenericReader parses JSON text from a stream, and send events synchronously to an
object implementing Handler concept .
It needs to allocate a stack for storing a single decoded string during
non - destructive parsing .
For in - situ parsing , the decoded string is directly written to the source
text string , no temporary buffer is required .
A GenericReader object can be reused for parsing multiple JSON text .
\ tparam SourceEncoding Encoding of the input stream .
\ tparam TargetEncoding Encoding of the parse output .
\ tparam StackAllocator Allocator type for stack .
*/
template < typename SourceEncoding , typename TargetEncoding , typename StackAllocator = CrtAllocator >
class GenericReader {
public :
typedef typename SourceEncoding : : Ch Ch ; //!< SourceEncoding character type
//! Constructor.
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
\ param stackCapacity stack capacity in bytes for storing a single decoded string . ( Only use for non - destructive parsing )
*/
GenericReader ( StackAllocator * stackAllocator = 0 , size_t stackCapacity = kDefaultStackCapacity ) : stack_ ( stackAllocator , stackCapacity ) , parseResult_ ( ) { }
//! Parse JSON text.
/*! \tparam parseFlags Combination of \ref ParseFlag.
\ tparam InputStream Type of input stream , implementing Stream concept .
\ tparam Handler Type of handler , implementing Handler concept .
\ param is Input stream to be parsed .
\ param handler The handler to receive events .
\ return Whether the parsing is successful .
*/
template < unsigned parseFlags , typename InputStream , typename Handler >
ParseResult Parse ( InputStream & is , Handler & handler ) {
if ( parseFlags & kParseIterativeFlag )
return IterativeParse < parseFlags > ( is , handler ) ;
parseResult_ . Clear ( ) ;
ClearStackOnExit scope ( * this ) ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
if ( RAPIDJSON_UNLIKELY ( is . Peek ( ) = = ' \0 ' ) ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorDocumentEmpty , is . Tell ( ) ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
}
else {
ParseValue < parseFlags > ( is , handler ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
if ( ! ( parseFlags & kParseStopWhenDoneFlag ) ) {
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
if ( RAPIDJSON_UNLIKELY ( is . Peek ( ) ! = ' \0 ' ) ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorDocumentRootNotSingular , is . Tell ( ) ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
}
}
}
return parseResult_ ;
}
//! Parse JSON text (with \ref kParseDefaultFlags)
/*! \tparam InputStream Type of input stream, implementing Stream concept
\ tparam Handler Type of handler , implementing Handler concept .
\ param is Input stream to be parsed .
\ param handler The handler to receive events .
\ return Whether the parsing is successful .
*/
template < typename InputStream , typename Handler >
ParseResult Parse ( InputStream & is , Handler & handler ) {
return Parse < kParseDefaultFlags > ( is , handler ) ;
}
//! Whether a parse error has occured in the last parsing.
bool HasParseError ( ) const { return parseResult_ . IsError ( ) ; }
//! Get the \ref ParseErrorCode of last parsing.
ParseErrorCode GetParseErrorCode ( ) const { return parseResult_ . Code ( ) ; }
//! Get the position of last parsing error in input, 0 otherwise.
size_t GetErrorOffset ( ) const { return parseResult_ . Offset ( ) ; }
protected :
void SetParseError ( ParseErrorCode code , size_t offset ) { parseResult_ . Set ( code , offset ) ; }
private :
// Prohibit copy constructor & assignment operator.
GenericReader ( const GenericReader & ) ;
GenericReader & operator = ( const GenericReader & ) ;
void ClearStack ( ) { stack_ . Clear ( ) ; }
// clear stack on any exit from ParseStream, e.g. due to exception
struct ClearStackOnExit {
explicit ClearStackOnExit ( GenericReader & r ) : r_ ( r ) { }
~ ClearStackOnExit ( ) { r_ . ClearStack ( ) ; }
private :
GenericReader & r_ ;
ClearStackOnExit ( 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 ( kParseErrorUnspecificSyntaxError , 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 . Tell ( ) ) ;
SkipWhitespace ( is ) ;
}
}
}
// Parse object: { string : value, ... }
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseObject ( InputStream & is , Handler & handler ) {
RAPIDJSON_ASSERT ( is . Peek ( ) = = ' { ' ) ;
is . Take ( ) ; // Skip '{'
if ( RAPIDJSON_UNLIKELY ( ! handler . StartObject ( ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
if ( Consume ( is , ' } ' ) ) {
if ( RAPIDJSON_UNLIKELY ( ! handler . EndObject ( 0 ) ) ) // empty object
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
return ;
}
for ( SizeType memberCount = 0 ; ; ) {
if ( RAPIDJSON_UNLIKELY ( is . Peek ( ) ! = ' " ' ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissName , is . Tell ( ) ) ;
ParseString < parseFlags > ( is , handler , true ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
if ( RAPIDJSON_UNLIKELY ( ! Consume ( is , ' : ' ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissColon , is . Tell ( ) ) ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
ParseValue < parseFlags > ( is , handler ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
+ + memberCount ;
switch ( is . Peek ( ) ) {
case ' , ' :
is . Take ( ) ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
break ;
case ' } ' :
is . Take ( ) ;
if ( RAPIDJSON_UNLIKELY ( ! handler . EndObject ( memberCount ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
return ;
default :
RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissCommaOrCurlyBracket , is . Tell ( ) ) ; break ; // This useless break is only for making warning and coverage 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, ... ]
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseArray ( InputStream & is , Handler & handler ) {
RAPIDJSON_ASSERT ( is . Peek ( ) = = ' [ ' ) ;
is . Take ( ) ; // Skip '['
if ( RAPIDJSON_UNLIKELY ( ! handler . StartArray ( ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
if ( Consume ( is , ' ] ' ) ) {
if ( RAPIDJSON_UNLIKELY ( ! handler . EndArray ( 0 ) ) ) // empty array
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
return ;
}
for ( SizeType elementCount = 0 ; ; ) {
ParseValue < parseFlags > ( is , handler ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
+ + elementCount ;
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 ( ) ) ;
if ( parseFlags & kParseTrailingCommasFlag ) {
if ( is . Peek ( ) = = ' ] ' ) {
if ( RAPIDJSON_UNLIKELY ( ! handler . EndArray ( elementCount ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
is . Take ( ) ;
return ;
}
}
}
}
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseNull ( InputStream & is , Handler & handler ) {
RAPIDJSON_ASSERT ( is . Peek ( ) = = ' n ' ) ;
is . Take ( ) ;
if ( RAPIDJSON_LIKELY ( Consume ( is , ' u ' ) & & Consume ( is , ' l ' ) & & Consume ( is , ' l ' ) ) ) {
if ( RAPIDJSON_UNLIKELY ( ! handler . Null ( ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorValueInvalid , is . Tell ( ) ) ;
}
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseTrue ( InputStream & is , Handler & handler ) {
RAPIDJSON_ASSERT ( is . Peek ( ) = = ' t ' ) ;
is . Take ( ) ;
if ( RAPIDJSON_LIKELY ( Consume ( is , ' r ' ) & & Consume ( is , ' u ' ) & & Consume ( is , ' e ' ) ) ) {
if ( RAPIDJSON_UNLIKELY ( ! handler . Bool ( true ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorValueInvalid , is . Tell ( ) ) ;
}
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseFalse ( InputStream & is , Handler & handler ) {
RAPIDJSON_ASSERT ( is . Peek ( ) = = ' f ' ) ;
is . Take ( ) ;
if ( RAPIDJSON_LIKELY ( Consume ( is , ' a ' ) & & Consume ( is , ' l ' ) & & Consume ( is , ' s ' ) & & Consume ( is , ' e ' ) ) ) {
if ( RAPIDJSON_UNLIKELY ( ! handler . Bool ( false ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorValueInvalid , is . Tell ( ) ) ;
}
template < typename InputStream >
RAPIDJSON_FORCEINLINE static bool Consume ( InputStream & is , typename InputStream : : 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().
template < typename InputStream >
unsigned ParseHex4 ( InputStream & is , size_t escapeOffset ) {
unsigned codepoint = 0 ;
for ( int i = 0 ; i < 4 ; i + + ) {
Ch c = is . Peek ( ) ;
codepoint < < = 4 ;
codepoint + = static_cast < unsigned > ( c ) ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
codepoint - = ' 0 ' ;
else if ( c > = ' A ' & & c < = ' F ' )
codepoint - = ' A ' - 10 ;
else if ( c > = ' a ' & & c < = ' f ' )
codepoint - = ' a ' - 10 ;
else {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorStringUnicodeEscapeInvalidHex , escapeOffset ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( 0 ) ;
}
is . Take ( ) ;
}
return codepoint ;
}
template < typename CharType >
class StackStream {
public :
typedef CharType Ch ;
StackStream ( internal : : Stack < StackAllocator > & stack ) : stack_ ( stack ) , length_ ( 0 ) { }
RAPIDJSON_FORCEINLINE void Put ( Ch c ) {
* stack_ . template Push < Ch > ( ) = c ;
+ + length_ ;
}
RAPIDJSON_FORCEINLINE void * Push ( SizeType count ) {
length_ + = count ;
return stack_ . template Push < Ch > ( count ) ;
}
size_t Length ( ) const { return length_ ; }
Ch * Pop ( ) {
return stack_ . template Pop < Ch > ( length_ ) ;
}
private :
StackStream ( const StackStream & ) ;
StackStream & operator = ( const StackStream & ) ;
internal : : Stack < StackAllocator > & stack_ ;
SizeType length_ ;
} ;
// Parse string and generate String event. Different code paths for kParseInsituFlag.
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseString ( InputStream & is , Handler & handler , bool isKey = false ) {
internal : : StreamLocalCopy < InputStream > copy ( is ) ;
InputStream & s ( copy . s ) ;
RAPIDJSON_ASSERT ( s . Peek ( ) = = ' \" ' ) ;
s . Take ( ) ; // Skip '\"'
bool success = false ;
if ( parseFlags & kParseInsituFlag ) {
typename InputStream : : Ch * head = s . PutBegin ( ) ;
ParseStringToStream < parseFlags , SourceEncoding , SourceEncoding > ( s , s ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
size_t length = s . PutEnd ( head ) - 1 ;
RAPIDJSON_ASSERT ( length < = 0xFFFFFFFF ) ;
const typename TargetEncoding : : Ch * const str = reinterpret_cast < typename TargetEncoding : : Ch * > ( head ) ;
success = ( isKey ? handler . Key ( str , SizeType ( length ) , false ) : handler . String ( str , SizeType ( length ) , false ) ) ;
}
else {
StackStream < typename TargetEncoding : : Ch > stackStream ( stack_ ) ;
ParseStringToStream < parseFlags , SourceEncoding , TargetEncoding > ( s , stackStream ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
SizeType length = static_cast < SizeType > ( stackStream . Length ( ) ) - 1 ;
const typename TargetEncoding : : Ch * const str = stackStream . Pop ( ) ;
success = ( isKey ? handler . Key ( str , length , true ) : handler . String ( str , length , true ) ) ;
}
if ( RAPIDJSON_UNLIKELY ( ! success ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , s . Tell ( ) ) ;
}
// Parse string to an output is
// This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
template < unsigned parseFlags , typename SEncoding , typename TEncoding , typename InputStream , typename OutputStream >
RAPIDJSON_FORCEINLINE void ParseStringToStream ( InputStream & is , OutputStream & os ) {
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
# define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
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 , 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 ,
Z16 , Z16 , Z16 , Z16 , Z16 , Z16 , Z16 , Z16
} ;
# undef Z16
//!@endcond
for ( ; ; ) {
// Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
if ( ! ( parseFlags & kParseValidateEncodingFlag ) )
ScanCopyUnescapedString ( is , os ) ;
Ch c = is . Peek ( ) ;
if ( RAPIDJSON_UNLIKELY ( c = = ' \\ ' ) ) { // Escape
size_t escapeOffset = is . Tell ( ) ; // For invalid escaping, report the inital '\\' as error offset
is . Take ( ) ;
Ch e = is . Peek ( ) ;
if ( ( sizeof ( Ch ) = = 1 | | unsigned ( e ) < 256 ) & & RAPIDJSON_LIKELY ( escape [ static_cast < unsigned char > ( e ) ] ) ) {
is . Take ( ) ;
os . Put ( static_cast < typename TEncoding : : Ch > ( escape [ static_cast < unsigned char > ( e ) ] ) ) ;
}
else if ( RAPIDJSON_LIKELY ( e = = ' u ' ) ) { // Unicode
is . Take ( ) ;
unsigned codepoint = ParseHex4 ( is , escapeOffset ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
if ( RAPIDJSON_UNLIKELY ( codepoint > = 0xD800 & & codepoint < = 0xDBFF ) ) {
// Handle UTF-16 surrogate pair
if ( RAPIDJSON_UNLIKELY ( ! Consume ( is , ' \\ ' ) | | ! Consume ( is , ' u ' ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorStringUnicodeSurrogateInvalid , escapeOffset ) ;
unsigned codepoint2 = ParseHex4 ( is , escapeOffset ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
if ( RAPIDJSON_UNLIKELY ( codepoint2 < 0xDC00 | | codepoint2 > 0xDFFF ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorStringUnicodeSurrogateInvalid , escapeOffset ) ;
codepoint = ( ( ( codepoint - 0xD800 ) < < 10 ) | ( codepoint2 - 0xDC00 ) ) + 0x10000 ;
}
TEncoding : : Encode ( os , codepoint ) ;
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorStringEscapeInvalid , escapeOffset ) ;
}
else if ( RAPIDJSON_UNLIKELY ( c = = ' " ' ) ) { // Closing double quote
is . Take ( ) ;
os . Put ( ' \0 ' ) ; // null-terminate the string
return ;
}
else if ( RAPIDJSON_UNLIKELY ( static_cast < unsigned > ( c ) < 0x20 ) ) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
if ( c = = ' \0 ' )
RAPIDJSON_PARSE_ERROR ( kParseErrorStringMissQuotationMark , is . Tell ( ) ) ;
else
RAPIDJSON_PARSE_ERROR ( kParseErrorStringEscapeInvalid , is . Tell ( ) ) ;
}
else {
size_t offset = is . Tell ( ) ;
if ( RAPIDJSON_UNLIKELY ( ( parseFlags & kParseValidateEncodingFlag ?
! Transcoder < SEncoding , TEncoding > : : Validate ( is , os ) :
! Transcoder < SEncoding , TEncoding > : : Transcode ( is , os ) ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorStringInvalidEncoding , offset ) ;
}
}
}
template < typename InputStream , typename OutputStream >
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString ( InputStream & , OutputStream & ) {
// 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 boundary and cause crash)
const char * nextAligned = reinterpret_cast < const char * > ( ( reinterpret_cast < 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 , 0x19 , 0x19 , 0x19 , 0x19 , 0x19 , 0x19 , 0x19 , 0x19 , 0x19 , 0x19 } ;
const __m128i dq = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & dquote [ 0 ] ) ) ;
const __m128i bs = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & bslash [ 0 ] ) ) ;
const __m128i sp = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & space [ 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 < 0x20 <=> 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 boundary and cause crash)
const char * nextAligned = reinterpret_cast < const char * > ( ( reinterpret_cast < 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 * > ( & dquote [ 0 ] ) ) ;
const __m128i bs = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & bslash [ 0 ] ) ) ;
const __m128i sp = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & space [ 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 < 0x20 <=> 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 unescaped 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 boundary and cause crash)
const char * nextAligned = reinterpret_cast < const char * > ( ( reinterpret_cast < 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 * > ( & dquote [ 0 ] ) ) ;
const __m128i bs = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & bslash [ 0 ] ) ) ;
const __m128i sp = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & space [ 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 < 0x20 <=> 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 , bool pushOnTake >
class NumberStream ;
template < typename InputStream >
class NumberStream < InputStream , false , false > {
public :
typedef typename InputStream : : Ch Ch ;
NumberStream ( GenericReader & reader , InputStream & s ) : is ( s ) { ( void ) reader ; }
~ NumberStream ( ) { }
RAPIDJSON_FORCEINLINE Ch Peek ( ) const { return is . Peek ( ) ; }
RAPIDJSON_FORCEINLINE Ch TakePush ( ) { return is . Take ( ) ; }
RAPIDJSON_FORCEINLINE Ch Take ( ) { return is . Take ( ) ; }
RAPIDJSON_FORCEINLINE void Push ( char ) { }
size_t Tell ( ) { return is . Tell ( ) ; }
size_t Length ( ) { return 0 ; }
const char * Pop ( ) { return 0 ; }
protected :
NumberStream & operator = ( const NumberStream & ) ;
InputStream & is ;
} ;
template < typename InputStream >
class NumberStream < InputStream , true , false > : public NumberStream < InputStream , false , false > {
typedef NumberStream < InputStream , false , false > Base ;
public :
NumberStream ( GenericReader & reader , InputStream & is ) : Base ( reader , is ) , stackStream ( reader . stack_ ) { }
~ NumberStream ( ) { }
RAPIDJSON_FORCEINLINE Ch TakePush ( ) {
stackStream . Put ( static_cast < char > ( Base : : is . Peek ( ) ) ) ;
return Base : : is . Take ( ) ;
}
RAPIDJSON_FORCEINLINE void Push ( char c ) {
stackStream . Put ( c ) ;
}
size_t Length ( ) { return stackStream . Length ( ) ; }
const char * Pop ( ) {
stackStream . Put ( ' \0 ' ) ;
return stackStream . Pop ( ) ;
}
private :
StackStream < char > stackStream ;
} ;
template < typename InputStream >
class NumberStream < InputStream , true , true > : public NumberStream < InputStream , 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 >
void ParseNumber ( InputStream & is , Handler & handler ) {
internal : : StreamLocalCopy < InputStream > copy ( is ) ;
NumberStream < InputStream ,
( ( 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
bool minus = Consume ( s , ' - ' ) ;
// Parse int: zero / ( digit1-9 *DIGIT )
unsigned i = 0 ;
uint64_t i64 = 0 ;
bool use64bit = false ;
int significandDigit = 0 ;
if ( RAPIDJSON_UNLIKELY ( s . Peek ( ) = = ' 0 ' ) ) {
i = 0 ;
s . TakePush ( ) ;
}
else if ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 1 ' & & s . Peek ( ) < = ' 9 ' ) ) {
i = static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
if ( minus )
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( RAPIDJSON_UNLIKELY ( i > = 214748364 ) ) { // 2^31 = 2147483648
if ( RAPIDJSON_LIKELY ( i ! = 214748364 | | s . Peek ( ) > ' 8 ' ) ) {
i64 = i ;
use64bit = true ;
break ;
}
}
i = i * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
}
else
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( RAPIDJSON_UNLIKELY ( i > = 429496729 ) ) { // 2^32 - 1 = 4294967295
if ( RAPIDJSON_LIKELY ( i ! = 429496729 | | s . Peek ( ) > ' 5 ' ) ) {
i64 = i ;
use64bit = true ;
break ;
}
}
i = i * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
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 ' ) & & Consume ( s , ' f ' ) ) ) {
d = ( minus ? - std : : numeric_limits < double > : : infinity ( ) : std : : numeric_limits < double > : : infinity ( ) ) ;
if ( RAPIDJSON_UNLIKELY ( s . Peek ( ) = = ' i ' & & ! ( Consume ( s , ' i ' ) & & Consume ( 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
RAPIDJSON_PARSE_ERROR ( kParseErrorValueInvalid , s . Tell ( ) ) ;
// Parse 64bit int
bool useDouble = false ;
if ( use64bit ) {
if ( minus )
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( RAPIDJSON_UNLIKELY ( i64 > = RAPIDJSON_UINT64_C2 ( 0x0CCCCCCC , 0xCCCCCCCC ) ) ) // 2^63 = 9223372036854775808
if ( RAPIDJSON_LIKELY ( i64 ! = RAPIDJSON_UINT64_C2 ( 0x0CCCCCCC , 0xCCCCCCCC ) | | s . Peek ( ) > ' 8 ' ) ) {
d = static_cast < double > ( i64 ) ;
useDouble = true ;
break ;
}
i64 = i64 * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
}
else
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( RAPIDJSON_UNLIKELY ( i64 > = RAPIDJSON_UINT64_C2 ( 0x19999999 , 0x99999999 ) ) ) // 2^64 - 1 = 18446744073709551615
if ( RAPIDJSON_LIKELY ( i64 ! = RAPIDJSON_UINT64_C2 ( 0x19999999 , 0x99999999 ) | | s . Peek ( ) > ' 5 ' ) ) {
d = static_cast < double > ( i64 ) ;
useDouble = true ;
break ;
}
i64 = i64 * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
}
}
// Force double for big integer
if ( useDouble ) {
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( RAPIDJSON_UNLIKELY ( d > = 1.7976931348623157e307 ) ) // DBL_MAX / 10.0
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberTooBig , startOffset ) ;
d = d * 10 + ( s . TakePush ( ) - ' 0 ' ) ;
}
}
// Parse frac = decimal-point 1*DIGIT
int expFrac = 0 ;
size_t decimalPosition ;
if ( Consume ( s , ' . ' ) ) {
decimalPosition = s . Length ( ) ;
if ( RAPIDJSON_UNLIKELY ( ! ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberMissFraction , s . Tell ( ) ) ;
if ( ! useDouble ) {
# if RAPIDJSON_64BIT
// Use i64 to store significand in 64-bit architecture
if ( ! use64bit )
i64 = i ;
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( i64 > RAPIDJSON_UINT64_C2 ( 0x1FFFFF , 0xFFFFFFFF ) ) // 2^53 - 1 for fast path
break ;
else {
i64 = i64 * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
- - expFrac ;
if ( i64 ! = 0 )
significandDigit + + ;
}
}
d = static_cast < double > ( i64 ) ;
# else
// Use double to store significand in 32-bit architecture
d = static_cast < double > ( use64bit ? i64 : i ) ;
# endif
useDouble = true ;
}
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
if ( significandDigit < 17 ) {
d = d * 10.0 + ( s . TakePush ( ) - ' 0 ' ) ;
- - expFrac ;
if ( RAPIDJSON_LIKELY ( d > 0.0 ) )
significandDigit + + ;
}
else
s . TakePush ( ) ;
}
}
else
decimalPosition = s . Length ( ) ; // decimal position at the end of integer.
// Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0 ;
if ( Consume ( s , ' e ' ) | | Consume ( s , ' E ' ) ) {
if ( ! useDouble ) {
d = static_cast < double > ( use64bit ? i64 : i ) ;
useDouble = true ;
}
bool expMinus = false ;
if ( Consume ( s , ' + ' ) )
;
else if ( Consume ( s , ' - ' ) )
expMinus = true ;
if ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
exp = static_cast < int > ( s . Take ( ) - ' 0 ' ) ;
if ( expMinus ) {
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
exp = exp * 10 + static_cast < int > ( s . Take ( ) - ' 0 ' ) ;
if ( exp > = 214748364 ) { // Issue #313: prevent overflow exponent
while ( RAPIDJSON_UNLIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) // Consume the rest of exponent
s . Take ( ) ;
}
}
}
else { // positive exp
int maxExp = 308 - expFrac ;
while ( RAPIDJSON_LIKELY ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) ) {
exp = exp * 10 + static_cast < int > ( s . Take ( ) - ' 0 ' ) ;
if ( RAPIDJSON_UNLIKELY ( exp > maxExp ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberTooBig , startOffset ) ;
}
}
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberMissExponent , s . Tell ( ) ) ;
if ( expMinus )
exp = - exp ;
}
// Finish parsing, call event according to the type of number.
bool cont = true ;
if ( parseFlags & kParseNumbersAsStringsFlag ) {
if ( parseFlags & kParseInsituFlag ) {
s . Pop ( ) ; // Pop stack no matter if it will be used or not.
typename InputStream : : Ch * head = is . PutBegin ( ) ;
const size_t length = s . Tell ( ) - startOffset ;
RAPIDJSON_ASSERT ( length < = 0xFFFFFFFF ) ;
// unable to insert the \0 character here, it will erase the comma after this number
const typename TargetEncoding : : Ch * const str = reinterpret_cast < typename TargetEncoding : : Ch * > ( head ) ;
cont = handler . RawNumber ( str , SizeType ( length ) , false ) ;
}
else {
SizeType numCharsToCopy = static_cast < SizeType > ( s . Length ( ) ) ;
StringStream srcStream ( s . Pop ( ) ) ;
StackStream < typename TargetEncoding : : Ch > dstStream ( stack_ ) ;
while ( numCharsToCopy - - ) {
Transcoder < UTF8 < > , TargetEncoding > : : Transcode ( srcStream , dstStream ) ;
}
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 ) ;
}
}
else {
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 , decimalPosition , 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
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseValue ( InputStream & is , Handler & handler ) {
switch ( is . Peek ( ) ) {
case ' n ' : ParseNull < parseFlags > ( is , handler ) ; break ;
case ' t ' : ParseTrue < parseFlags > ( is , handler ) ; break ;
case ' f ' : ParseFalse < parseFlags > ( is , handler ) ; break ;
case ' " ' : ParseString < parseFlags > ( is , handler ) ; break ;
case ' { ' : ParseObject < parseFlags > ( is , handler ) ; break ;
case ' [ ' : ParseArray < parseFlags > ( is , handler ) ; break ;
default :
ParseNumber < parseFlags > ( is , handler ) ;
break ;
}
}
// Iterative Parsing
// States
enum IterativeParsingState {
IterativeParsingStartState = 0 ,
IterativeParsingFinishState ,
IterativeParsingErrorState ,
// Object states
IterativeParsingObjectInitialState ,
IterativeParsingMemberKeyState ,
IterativeParsingKeyValueDelimiterState ,
IterativeParsingMemberValueState ,
IterativeParsingMemberDelimiterState ,
IterativeParsingObjectFinishState ,
// Array states
IterativeParsingArrayInitialState ,
IterativeParsingElementState ,
IterativeParsingElementDelimiterState ,
IterativeParsingArrayFinishState ,
// Single value state
IterativeParsingValueState
} ;
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 } ;
// Tokens
enum Token {
LeftBracketToken = 0 ,
RightBracketToken ,
LeftCurlyBracketToken ,
RightCurlyBracketToken ,
CommaToken ,
ColonToken ,
StringToken ,
FalseToken ,
TrueToken ,
NullToken ,
NumberToken ,
kTokenCount
} ;
RAPIDJSON_FORCEINLINE Token Tokenize ( Ch c ) {
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
# define N NumberToken
# define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
// Maps from ASCII to Token
static const unsigned char tokenMap [ 256 ] = {
N16 , // 00~0F
N16 , // 10~1F
N , N , StringToken , N , N , N , N , N , N , N , N , N , CommaToken , N , N , N , // 20~2F
N , N , N , N , N , N , N , N , N , N , ColonToken , N , N , N , N , N , // 30~3F
N16 , // 40~4F
N , N , N , N , N , N , N , N , N , N , N , LeftBracketToken , N , RightBracketToken , 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 , TrueToken , N , N , N , N , N , N , LeftCurlyBracketToken , N , RightCurlyBracketToken , N , N , // 70~7F
N16 , N16 , N16 , N16 , N16 , N16 , N16 , N16 // 80~FF
} ;
# undef N
# undef N16
//!@endcond
if ( sizeof ( Ch ) = = 1 | | static_cast < unsigned > ( c ) < 256 )
return static_cast < Token > ( tokenMap [ static_cast < unsigned char > ( c ) ] ) ;
else
return NumberToken ;
}
RAPIDJSON_FORCEINLINE IterativeParsingState Predict ( IterativeParsingState state , Token token ) {
// current state x one lookahead token -> new state
static const char G [ cIterativeParsingStateCount ] [ kTokenCount ] = {
// Start
{
IterativeParsingArrayInitialState , // Left bracket
IterativeParsingErrorState , // Right bracket
IterativeParsingObjectInitialState , // Left curly bracket
IterativeParsingErrorState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingValueState , // String
IterativeParsingValueState , // False
IterativeParsingValueState , // True
IterativeParsingValueState , // Null
IterativeParsingValueState // Number
} ,
// Finish(sink state)
{
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState
} ,
// Error(sink state)
{
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState
} ,
// ObjectInitial
{
IterativeParsingErrorState , // Left bracket
IterativeParsingErrorState , // Right bracket
IterativeParsingErrorState , // Left curly bracket
IterativeParsingObjectFinishState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingMemberKeyState , // String
IterativeParsingErrorState , // False
IterativeParsingErrorState , // True
IterativeParsingErrorState , // Null
IterativeParsingErrorState // Number
} ,
// MemberKey
{
IterativeParsingErrorState , // Left bracket
IterativeParsingErrorState , // Right bracket
IterativeParsingErrorState , // Left curly bracket
IterativeParsingErrorState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingKeyValueDelimiterState , // Colon
IterativeParsingErrorState , // String
IterativeParsingErrorState , // False
IterativeParsingErrorState , // True
IterativeParsingErrorState , // Null
IterativeParsingErrorState // Number
} ,
// KeyValueDelimiter
{
IterativeParsingArrayInitialState , // Left bracket(push MemberValue state)
IterativeParsingErrorState , // Right bracket
IterativeParsingObjectInitialState , // Left curly bracket(push MemberValue state)
IterativeParsingErrorState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingMemberValueState , // String
IterativeParsingMemberValueState , // False
IterativeParsingMemberValueState , // True
IterativeParsingMemberValueState , // Null
IterativeParsingMemberValueState // Number
} ,
// MemberValue
{
IterativeParsingErrorState , // Left bracket
IterativeParsingErrorState , // Right bracket
IterativeParsingErrorState , // Left curly bracket
IterativeParsingObjectFinishState , // Right curly bracket
IterativeParsingMemberDelimiterState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingErrorState , // String
IterativeParsingErrorState , // False
IterativeParsingErrorState , // True
IterativeParsingErrorState , // Null
IterativeParsingErrorState // Number
} ,
// MemberDelimiter
{
IterativeParsingErrorState , // Left bracket
IterativeParsingErrorState , // Right bracket
IterativeParsingErrorState , // Left curly bracket
IterativeParsingObjectFinishState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingMemberKeyState , // String
IterativeParsingErrorState , // False
IterativeParsingErrorState , // True
IterativeParsingErrorState , // Null
IterativeParsingErrorState // Number
} ,
// ObjectFinish(sink state)
{
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState
} ,
// ArrayInitial
{
IterativeParsingArrayInitialState , // Left bracket(push Element state)
IterativeParsingArrayFinishState , // Right bracket
IterativeParsingObjectInitialState , // Left curly bracket(push Element state)
IterativeParsingErrorState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingElementState , // String
IterativeParsingElementState , // False
IterativeParsingElementState , // True
IterativeParsingElementState , // Null
IterativeParsingElementState // Number
} ,
// Element
{
IterativeParsingErrorState , // Left bracket
IterativeParsingArrayFinishState , // Right bracket
IterativeParsingErrorState , // Left curly bracket
IterativeParsingErrorState , // Right curly bracket
IterativeParsingElementDelimiterState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingErrorState , // String
IterativeParsingErrorState , // False
IterativeParsingErrorState , // True
IterativeParsingErrorState , // Null
IterativeParsingErrorState // Number
} ,
// ElementDelimiter
{
IterativeParsingArrayInitialState , // Left bracket(push Element state)
IterativeParsingArrayFinishState , // Right bracket
IterativeParsingObjectInitialState , // Left curly bracket(push Element state)
IterativeParsingErrorState , // Right curly bracket
IterativeParsingErrorState , // Comma
IterativeParsingErrorState , // Colon
IterativeParsingElementState , // String
IterativeParsingElementState , // False
IterativeParsingElementState , // True
IterativeParsingElementState , // Null
IterativeParsingElementState // Number
} ,
// ArrayFinish(sink state)
{
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState
} ,
// Single Value (sink state)
{
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState , IterativeParsingErrorState ,
IterativeParsingErrorState
}
} ; // End of G
return static_cast < IterativeParsingState > ( G [ state ] [ token ] ) ;
}
// Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
// May return a new state on state pop.
template < unsigned parseFlags , typename InputStream , typename Handler >
RAPIDJSON_FORCEINLINE IterativeParsingState Transit ( IterativeParsingState src , Token token , IterativeParsingState dst , InputStream & is , Handler & handler ) {
( void ) token ;
switch ( dst ) {
case IterativeParsingErrorState :
return dst ;
case IterativeParsingObjectInitialState :
case IterativeParsingArrayInitialState :
{
// Push the state(Element or MemeberValue) if we are nested in another array or value of member.
// In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
IterativeParsingState n = src ;
if ( src = = IterativeParsingArrayInitialState | | src = = IterativeParsingElementDelimiterState )
n = IterativeParsingElementState ;
else if ( src = = IterativeParsingKeyValueDelimiterState )
n = IterativeParsingMemberValueState ;
// Push current state.
* stack_ . template Push < SizeType > ( 1 ) = n ;
// Initialize and push the member/element count.
* stack_ . template Push < SizeType > ( 1 ) = 0 ;
// Call handler
bool hr = ( dst = = IterativeParsingObjectInitialState ) ? handler . StartObject ( ) : handler . StartArray ( ) ;
// On handler short circuits the parsing.
if ( ! hr ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorTermination , is . Tell ( ) ) ;
return IterativeParsingErrorState ;
}
else {
is . Take ( ) ;
return dst ;
}
}
case IterativeParsingMemberKeyState :
ParseString < parseFlags > ( is , handler , true ) ;
if ( HasParseError ( ) )
return IterativeParsingErrorState ;
else
return dst ;
case IterativeParsingKeyValueDelimiterState :
RAPIDJSON_ASSERT ( token = = ColonToken ) ;
is . Take ( ) ;
return dst ;
case IterativeParsingMemberValueState :
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
ParseValue < parseFlags > ( is , handler ) ;
if ( HasParseError ( ) ) {
return IterativeParsingErrorState ;
}
return dst ;
case IterativeParsingElementState :
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
ParseValue < parseFlags > ( is , handler ) ;
if ( HasParseError ( ) ) {
return IterativeParsingErrorState ;
}
return dst ;
case IterativeParsingMemberDelimiterState :
case IterativeParsingElementDelimiterState :
is . Take ( ) ;
// Update member/element count.
* stack_ . template Top < SizeType > ( ) = * stack_ . template Top < SizeType > ( ) + 1 ;
return dst ;
case IterativeParsingObjectFinishState :
{
// Transit from delimiter is only allowed when trailing commas are enabled
if ( ! ( parseFlags & kParseTrailingCommasFlag ) & & src = = IterativeParsingMemberDelimiterState ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorObjectMissName , is . Tell ( ) ) ;
return IterativeParsingErrorState ;
}
// Get member count.
SizeType c = * stack_ . template Pop < SizeType > ( 1 ) ;
// If the object is not empty, count the last member.
if ( src = = IterativeParsingMemberValueState )
+ + c ;
// Restore the state.
IterativeParsingState n = static_cast < IterativeParsingState > ( * stack_ . template Pop < SizeType > ( 1 ) ) ;
// Transit to Finish state if this is the topmost scope.
if ( n = = IterativeParsingStartState )
n = IterativeParsingFinishState ;
// Call handler
bool hr = handler . EndObject ( c ) ;
// On handler short circuits the parsing.
if ( ! hr ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorTermination , is . Tell ( ) ) ;
return IterativeParsingErrorState ;
}
else {
is . Take ( ) ;
return n ;
}
}
case IterativeParsingArrayFinishState :
{
// Transit from delimiter is only allowed when trailing commas are enabled
if ( ! ( parseFlags & kParseTrailingCommasFlag ) & & src = = IterativeParsingElementDelimiterState ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorValueInvalid , is . Tell ( ) ) ;
return IterativeParsingErrorState ;
}
// Get element count.
SizeType c = * stack_ . template Pop < SizeType > ( 1 ) ;
// If the array is not empty, count the last element.
if ( src = = IterativeParsingElementState )
+ + c ;
// Restore the state.
IterativeParsingState n = static_cast < IterativeParsingState > ( * stack_ . template Pop < SizeType > ( 1 ) ) ;
// Transit to Finish state if this is the topmost scope.
if ( n = = IterativeParsingStartState )
n = IterativeParsingFinishState ;
// Call handler
bool hr = handler . EndArray ( c ) ;
// On handler short circuits the parsing.
if ( ! hr ) {
RAPIDJSON_PARSE_ERROR_NORETURN ( kParseErrorTermination , is . Tell ( ) ) ;
return IterativeParsingErrorState ;
}
else {
is . Take ( ) ;
return n ;
}
}
default :
// This branch is for IterativeParsingValueState actually.
// Use `default:` rather than
// `case IterativeParsingValueState:` is for code coverage.
// The IterativeParsingStartState is not enumerated in this switch-case.
// It is impossible for that case. And it can be caught by following assertion.
// The IterativeParsingFinishState is not enumerated in this switch-case either.
// It is a "derivative" state which cannot triggered from Predict() directly.
// Therefore it cannot happen here. And it can be caught by following assertion.
RAPIDJSON_ASSERT ( dst = = IterativeParsingValueState ) ;
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
ParseValue < parseFlags > ( is , handler ) ;
if ( HasParseError ( ) ) {
return IterativeParsingErrorState ;
}
return IterativeParsingFinishState ;
}
}
template < typename InputStream >
void HandleError ( IterativeParsingState src , InputStream & is ) {
if ( HasParseError ( ) ) {
// Error flag has been set.
return ;
}
switch ( src ) {
case IterativeParsingStartState : RAPIDJSON_PARSE_ERROR ( kParseErrorDocumentEmpty , is . Tell ( ) ) ; return ;
case IterativeParsingFinishState : RAPIDJSON_PARSE_ERROR ( kParseErrorDocumentRootNotSingular , is . Tell ( ) ) ; return ;
case IterativeParsingObjectInitialState :
case IterativeParsingMemberDelimiterState : RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissName , is . Tell ( ) ) ; return ;
case IterativeParsingMemberKeyState : RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissColon , is . Tell ( ) ) ; return ;
case IterativeParsingMemberValueState : RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissCommaOrCurlyBracket , is . Tell ( ) ) ; return ;
case IterativeParsingKeyValueDelimiterState :
case IterativeParsingArrayInitialState :
case IterativeParsingElementDelimiterState : RAPIDJSON_PARSE_ERROR ( kParseErrorValueInvalid , is . Tell ( ) ) ; return ;
default : RAPIDJSON_ASSERT ( src = = IterativeParsingElementState ) ; RAPIDJSON_PARSE_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , is . Tell ( ) ) ; return ;
}
}
template < unsigned parseFlags , typename InputStream , typename Handler >
ParseResult IterativeParse ( InputStream & is , Handler & handler ) {
parseResult_ . Clear ( ) ;
ClearStackOnExit scope ( * this ) ;
IterativeParsingState state = IterativeParsingStartState ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
while ( is . Peek ( ) ! = ' \0 ' ) {
Token t = Tokenize ( is . Peek ( ) ) ;
IterativeParsingState n = Predict ( state , t ) ;
IterativeParsingState d = Transit < parseFlags > ( state , t , n , is , handler ) ;
if ( d = = IterativeParsingErrorState ) {
HandleError ( state , is ) ;
break ;
}
state = d ;
// Do not further consume streams if a root JSON has been parsed.
if ( ( parseFlags & kParseStopWhenDoneFlag ) & & state = = IterativeParsingFinishState )
break ;
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
}
// Handle the end of file.
if ( state ! = IterativeParsingFinishState )
HandleError ( state , is ) ;
return parseResult_ ;
}
static const size_t kDefaultStackCapacity = 256 ; //!< Default stack capacity in bytes for storing a single decoded string.
internal : : Stack < StackAllocator > stack_ ; //!< A stack for storing decoded string temporarily during non-destructive parsing.
ParseResult parseResult_ ;
} ; // class GenericReader
//! Reader with UTF8 encoding and default allocator.
typedef GenericReader < UTF8 < > , UTF8 < > > Reader ;
RAPIDJSON_NAMESPACE_END
# ifdef __clang__
RAPIDJSON_DIAG_POP
# endif
# ifdef __GNUC__
RAPIDJSON_DIAG_POP
# endif
# ifdef _MSC_VER
RAPIDJSON_DIAG_POP
# endif
# endif // RAPIDJSON_READER_H_