mirror of
https://github.com/monero-project/monero.git
synced 2025-08-08 12:32:20 -04:00
no longer need to pass the size to rapidjson
This commit is contained in:
parent
bd8e0fd2a1
commit
32a26332f8
31 changed files with 3763 additions and 1143 deletions
497
external/rapidjson/reader.h
vendored
497
external/rapidjson/reader.h
vendored
|
@ -1,22 +1,16 @@
|
|||
// Copyright (C) 2011 Milo Yip
|
||||
// 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.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// 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
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
// 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_
|
||||
|
@ -26,8 +20,8 @@
|
|||
#include "rapidjson.h"
|
||||
#include "encodings.h"
|
||||
#include "internal/meta.h"
|
||||
#include "internal/pow10.h"
|
||||
#include "internal/stack.h"
|
||||
#include "internal/strtod.h"
|
||||
|
||||
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
|
@ -45,6 +39,17 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
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
|
||||
|
@ -116,20 +121,33 @@ RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
|||
|
||||
#include "error/error.h" // ParseErrorCode, ParseResult
|
||||
|
||||
namespace rapidjson {
|
||||
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 {
|
||||
kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
|
||||
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.
|
||||
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.
|
||||
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -244,27 +262,27 @@ void SkipWhitespace(InputStream& is) {
|
|||
#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;
|
||||
// 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) & ~15);
|
||||
while (p != nextAligned)
|
||||
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((const __m128i *)&whitespace[0]);
|
||||
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((const __m128i *)p);
|
||||
const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
|
||||
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;
|
||||
|
@ -281,39 +299,39 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
|||
|
||||
//! 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;
|
||||
// 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) & ~15);
|
||||
while (p != nextAligned)
|
||||
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
|
||||
++p;
|
||||
else
|
||||
return p;
|
||||
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
|
||||
static const char whitespaces[4][17] = {
|
||||
" ",
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
||||
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
|
||||
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
|
||||
static const char whitespaces[4][17] = {
|
||||
" ",
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
||||
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
|
||||
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
|
||||
|
||||
const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
|
||||
const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
|
||||
const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
|
||||
const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
|
||||
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((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 = (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
|
||||
#ifdef _MSC_VER // Find the index of first non-whitespace
|
||||
unsigned long offset;
|
||||
|
@ -365,7 +383,7 @@ public:
|
|||
typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
|
||||
|
||||
//! Constructor.
|
||||
/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
||||
/*! \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_() {}
|
||||
|
@ -387,7 +405,8 @@ public:
|
|||
|
||||
ClearStackOnExit scope(*this);
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
|
||||
if (is.Peek() == '\0') {
|
||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
||||
|
@ -398,7 +417,8 @@ public:
|
|||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
|
||||
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
|
||||
if (is.Peek() != '\0') {
|
||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||
|
@ -451,6 +471,40 @@ private:
|
|||
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
||||
};
|
||||
|
||||
template<unsigned parseFlags, typename InputStream>
|
||||
void SkipWhitespaceAndComments(InputStream& is) {
|
||||
SkipWhitespace(is);
|
||||
|
||||
if (parseFlags & kParseCommentsFlag) {
|
||||
while (is.Peek() == '/') {
|
||||
is.Take();
|
||||
|
||||
if (is.Peek() == '*') {
|
||||
is.Take();
|
||||
while (true) {
|
||||
if (is.Peek() == '\0')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
|
||||
if (is.Take() == '*') {
|
||||
if (is.Peek() == '\0')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
|
||||
if (is.Take() == '/')
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (is.Peek() == '/') {
|
||||
is.Take();
|
||||
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) {
|
||||
|
@ -460,7 +514,8 @@ private:
|
|||
if (!handler.StartObject())
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
if (is.Peek() == '}') {
|
||||
is.Take();
|
||||
|
@ -476,28 +531,35 @@ private:
|
|||
ParseString<parseFlags>(is, handler, true);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
if (is.Take() != ':')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
ParseValue<parseFlags>(is, handler);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
++memberCount;
|
||||
|
||||
switch (is.Take()) {
|
||||
case ',': SkipWhitespace(is); break;
|
||||
case ',':
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
break;
|
||||
case '}':
|
||||
if (!handler.EndObject(memberCount))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
else
|
||||
return;
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||
return;
|
||||
default:
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -511,7 +573,8 @@ private:
|
|||
if (!handler.StartArray())
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
if (is.Peek() == ']') {
|
||||
is.Take();
|
||||
|
@ -525,16 +588,21 @@ private:
|
|||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
++elementCount;
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
|
||||
switch (is.Take()) {
|
||||
case ',': SkipWhitespace(is); break;
|
||||
case ',':
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
break;
|
||||
case ']':
|
||||
if (!handler.EndArray(elementCount))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||
else
|
||||
return;
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||
return;
|
||||
default:
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -600,21 +668,27 @@ private:
|
|||
return codepoint;
|
||||
}
|
||||
|
||||
template <typename CharType>
|
||||
class StackStream {
|
||||
public:
|
||||
typedef typename TargetEncoding::Ch Ch;
|
||||
typedef CharType Ch;
|
||||
|
||||
StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
|
||||
RAPIDJSON_FORCEINLINE void Put(Ch c) {
|
||||
*stack_.template Push<Ch>() = c;
|
||||
++length_;
|
||||
}
|
||||
internal::Stack<StackAllocator>& stack_;
|
||||
SizeType length_;
|
||||
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.
|
||||
|
@ -630,15 +704,16 @@ private:
|
|||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
size_t length = s.PutEnd(head) - 1;
|
||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||
const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head;
|
||||
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 stackStream(stack_);
|
||||
StackStream<typename TargetEncoding::Ch> stackStream(stack_);
|
||||
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
const typename TargetEncoding::Ch* const str = stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_);
|
||||
success = (isKey ? handler.Key(str, stackStream.length_ - 1, true) : handler.String(str, stackStream.length_ - 1, true));
|
||||
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 (!success)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||
|
@ -668,16 +743,17 @@ private:
|
|||
if (c == '\\') { // Escape
|
||||
is.Take();
|
||||
Ch e = is.Take();
|
||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
|
||||
os.Put(escape[(unsigned char)e]);
|
||||
}
|
||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[static_cast<unsigned char>(e)])
|
||||
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
||||
else if (e == 'u') { // Unicode
|
||||
unsigned codepoint = ParseHex4(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
||||
// Handle UTF-16 surrogate pair
|
||||
if (is.Take() != '\\' || is.Take() != 'u')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
||||
unsigned codepoint2 = ParseHex4(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
||||
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
||||
|
@ -694,7 +770,7 @@ private:
|
|||
}
|
||||
else if (c == '\0')
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
||||
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
else if (static_cast<unsigned>(c) < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
||||
else {
|
||||
if (parseFlags & kParseValidateEncodingFlag ?
|
||||
|
@ -705,22 +781,55 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
inline double StrtodFastPath(double significand, int exp) {
|
||||
// Fast path only works on limited range of values.
|
||||
// But for simplicity and performance, currently only implement this.
|
||||
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||
if (exp < -308)
|
||||
return 0.0;
|
||||
else if (exp >= 0)
|
||||
return significand * internal::Pow10(exp);
|
||||
else
|
||||
return significand / internal::Pow10(-exp);
|
||||
}
|
||||
template<typename InputStream, bool backup>
|
||||
class NumberStream;
|
||||
|
||||
template<typename InputStream>
|
||||
class NumberStream<InputStream, false> {
|
||||
public:
|
||||
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(); }
|
||||
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> : public NumberStream<InputStream, false> {
|
||||
typedef NumberStream<InputStream, false> Base;
|
||||
public:
|
||||
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
|
||||
~NumberStream() {}
|
||||
|
||||
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
||||
stackStream.Put(static_cast<char>(Base::is.Peek()));
|
||||
return Base::is.Take();
|
||||
}
|
||||
|
||||
size_t Length() { return stackStream.Length(); }
|
||||
|
||||
const char* Pop() {
|
||||
stackStream.Put('\0');
|
||||
return stackStream.Pop();
|
||||
}
|
||||
|
||||
private:
|
||||
StackStream<char> stackStream;
|
||||
};
|
||||
|
||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||
void ParseNumber(InputStream& is, Handler& handler) {
|
||||
internal::StreamLocalCopy<InputStream> copy(is);
|
||||
InputStream& s(copy.s);
|
||||
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
|
||||
|
||||
// Parse minus
|
||||
bool minus = false;
|
||||
|
@ -733,12 +842,13 @@ private:
|
|||
unsigned i = 0;
|
||||
uint64_t i64 = 0;
|
||||
bool use64bit = false;
|
||||
int significandDigit = 0;
|
||||
if (s.Peek() == '0') {
|
||||
i = 0;
|
||||
s.Take();
|
||||
s.TakePush();
|
||||
}
|
||||
else if (s.Peek() >= '1' && s.Peek() <= '9') {
|
||||
i = static_cast<unsigned>(s.Take() - '0');
|
||||
i = static_cast<unsigned>(s.TakePush() - '0');
|
||||
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
|
@ -749,7 +859,8 @@ private:
|
|||
break;
|
||||
}
|
||||
}
|
||||
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||
i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
|
||||
significandDigit++;
|
||||
}
|
||||
else
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
|
@ -760,35 +871,38 @@ private:
|
|||
break;
|
||||
}
|
||||
}
|
||||
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||
i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
|
||||
significandDigit++;
|
||||
}
|
||||
}
|
||||
else
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
|
||||
|
||||
// Parse 64bit int
|
||||
double d = 0.0;
|
||||
bool useDouble = false;
|
||||
double d = 0.0;
|
||||
if (use64bit) {
|
||||
if (minus)
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
|
||||
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
|
||||
d = (double)i64;
|
||||
d = i64;
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
|
||||
significandDigit++;
|
||||
}
|
||||
else
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615
|
||||
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {
|
||||
d = (double)i64;
|
||||
d = i64;
|
||||
useDouble = true;
|
||||
break;
|
||||
}
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
|
||||
significandDigit++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -797,53 +911,64 @@ private:
|
|||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
d = d * 10 + (s.TakePush() - '0');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse frac = decimal-point 1*DIGIT
|
||||
int expFrac = 0;
|
||||
size_t decimalPosition;
|
||||
if (s.Peek() == '.') {
|
||||
s.Take();
|
||||
decimalPosition = s.Length();
|
||||
|
||||
if (!(s.Peek() >= '0' && s.Peek() <= '9'))
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
|
||||
|
||||
#if RAPIDJSON_64BIT
|
||||
// Use i64 to store significand in 64-bit architecture
|
||||
if (!useDouble) {
|
||||
#if RAPIDJSON_64BIT
|
||||
// Use i64 to store significand in 64-bit architecture
|
||||
if (!use64bit)
|
||||
i64 = i;
|
||||
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))
|
||||
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
|
||||
break;
|
||||
else {
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
||||
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
|
||||
--expFrac;
|
||||
if (i64 != 0)
|
||||
significandDigit++;
|
||||
}
|
||||
}
|
||||
|
||||
d = (double)i64;
|
||||
}
|
||||
d = static_cast<double>(i64);
|
||||
#else
|
||||
// Use double to store significand in 32-bit architecture
|
||||
if (!useDouble)
|
||||
d = use64bit ? (double)i64 : (double)i;
|
||||
// Use double to store significand in 32-bit architecture
|
||||
d = static_cast<double>(use64bit ? i64 : i);
|
||||
#endif
|
||||
useDouble = true;
|
||||
useDouble = true;
|
||||
}
|
||||
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
d = d * 10 + (s.Take() - '0');
|
||||
--expFrac;
|
||||
if (significandDigit < 17) {
|
||||
d = d * 10.0 + (s.TakePush() - '0');
|
||||
--expFrac;
|
||||
if (d > 0.0)
|
||||
significandDigit++;
|
||||
}
|
||||
else
|
||||
s.TakePush();
|
||||
}
|
||||
|
||||
if (expFrac == 0)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
|
||||
}
|
||||
else
|
||||
decimalPosition = s.Length(); // decimal position at the end of integer.
|
||||
|
||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||
int exp = 0;
|
||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
||||
if (!useDouble) {
|
||||
d = use64bit ? (double)i64 : (double)i;
|
||||
d = use64bit ? i64 : i;
|
||||
useDouble = true;
|
||||
}
|
||||
s.Take();
|
||||
|
@ -857,11 +982,23 @@ private:
|
|||
}
|
||||
|
||||
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = s.Take() - '0';
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + (s.Take() - '0');
|
||||
if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first.
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
exp = static_cast<int>(s.Take() - '0');
|
||||
if (expMinus) {
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||
if (exp >= 214748364) { // Issue #313: prevent overflow exponent
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent
|
||||
s.Take();
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // positive exp
|
||||
int maxExp = 308 - expFrac;
|
||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||
if (exp > maxExp)
|
||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -873,28 +1010,28 @@ private:
|
|||
|
||||
// Finish parsing, call event according to the type of number.
|
||||
bool cont = true;
|
||||
size_t length = s.Length();
|
||||
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
||||
|
||||
if (useDouble) {
|
||||
int expSum = exp + expFrac;
|
||||
if (expSum < -308) {
|
||||
// Prevent expSum < -308, making Pow10(expSum) = 0
|
||||
d = StrtodFastPath(d, exp);
|
||||
d = StrtodFastPath(d, expFrac);
|
||||
}
|
||||
int p = exp + expFrac;
|
||||
if (parseFlags & kParseFullPrecisionFlag)
|
||||
d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
|
||||
else
|
||||
d = StrtodFastPath(d, expSum);
|
||||
d = internal::StrtodNormalPrecision(d, p);
|
||||
|
||||
cont = handler.Double(minus ? -d : d);
|
||||
}
|
||||
else {
|
||||
if (use64bit) {
|
||||
if (minus)
|
||||
cont = handler.Int64(-(int64_t)i64);
|
||||
cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
|
||||
else
|
||||
cont = handler.Uint64(i64);
|
||||
}
|
||||
else {
|
||||
if (minus)
|
||||
cont = handler.Int(-(int)i);
|
||||
cont = handler.Int(static_cast<int32_t>(~i + 1));
|
||||
else
|
||||
cont = handler.Uint(i);
|
||||
}
|
||||
|
@ -913,7 +1050,10 @@ private:
|
|||
case '"': ParseString<parseFlags>(is, handler); break;
|
||||
case '{': ParseObject<parseFlags>(is, handler); break;
|
||||
case '[': ParseArray <parseFlags>(is, handler); break;
|
||||
default : ParseNumber<parseFlags>(is, handler);
|
||||
default :
|
||||
ParseNumber<parseFlags>(is, handler);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,11 +1080,11 @@ private:
|
|||
IterativeParsingArrayFinishState,
|
||||
|
||||
// Single value state
|
||||
IterativeParsingValueState,
|
||||
|
||||
cIterativeParsingStateCount
|
||||
IterativeParsingValueState
|
||||
};
|
||||
|
||||
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
|
||||
|
||||
// Tokens
|
||||
enum Token {
|
||||
LeftBracketToken = 0,
|
||||
|
@ -986,8 +1126,8 @@ private:
|
|||
#undef N16
|
||||
//!@endcond
|
||||
|
||||
if (sizeof(Ch) == 1 || unsigned(c) < 256)
|
||||
return (Token)tokenMap[(unsigned char)c];
|
||||
if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
|
||||
return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
|
||||
else
|
||||
return NumberToken;
|
||||
}
|
||||
|
@ -1153,21 +1293,16 @@ private:
|
|||
}
|
||||
}; // 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 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 IterativeParsingStartState:
|
||||
RAPIDJSON_ASSERT(false);
|
||||
return IterativeParsingErrorState;
|
||||
|
||||
case IterativeParsingFinishState:
|
||||
return dst;
|
||||
|
||||
case IterativeParsingErrorState:
|
||||
return dst;
|
||||
|
||||
|
@ -1206,12 +1341,9 @@ private:
|
|||
return dst;
|
||||
|
||||
case IterativeParsingKeyValueDelimiterState:
|
||||
if (token == ColonToken) {
|
||||
is.Take();
|
||||
return dst;
|
||||
}
|
||||
else
|
||||
return IterativeParsingErrorState;
|
||||
RAPIDJSON_ASSERT(token == ColonToken);
|
||||
is.Take();
|
||||
return dst;
|
||||
|
||||
case IterativeParsingMemberValueState:
|
||||
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
|
||||
|
@ -1286,17 +1418,25 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
case IterativeParsingValueState:
|
||||
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;
|
||||
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false);
|
||||
return IterativeParsingErrorState;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1308,14 +1448,14 @@ private:
|
|||
}
|
||||
|
||||
switch (src) {
|
||||
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
|
||||
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||
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());
|
||||
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||
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 IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
|
||||
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1325,7 +1465,8 @@ private:
|
|||
ClearStackOnExit scope(*this);
|
||||
IterativeParsingState state = IterativeParsingStartState;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
while (is.Peek() != '\0') {
|
||||
Token t = Tokenize(is.Peek());
|
||||
IterativeParsingState n = Predict(state, t);
|
||||
|
@ -1342,7 +1483,8 @@ private:
|
|||
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
||||
break;
|
||||
|
||||
SkipWhitespace(is);
|
||||
SkipWhitespaceAndComments<parseFlags>(is);
|
||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||
}
|
||||
|
||||
// Handle the end of file.
|
||||
|
@ -1360,7 +1502,16 @@ private:
|
|||
//! Reader with UTF8 encoding and default allocator.
|
||||
typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
||||
|
||||
} // namespace rapidjson
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue