RapidJSON updated (current master).

This commit is contained in:
Kirill Kirilenko 2016-09-26 20:02:35 +03:00
parent 83d330f47a
commit 9ec8037240
30 changed files with 9253 additions and 7925 deletions

View file

@ -179,7 +179,8 @@ public:
size = RAPIDJSON_ALIGN(size); size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size; chunkHead_->size += size;
@ -211,11 +212,13 @@ public:
} }
// Realloc process: allocate and copy memory, do not free original buffer. // Realloc process: allocate and copy memory, do not free original buffer.
void* newBuffer = Malloc(newSize); if (void* newBuffer = Malloc(newSize)) {
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. if (originalSize)
if (originalSize) std::memcpy(newBuffer, originalPtr, originalSize);
std::memcpy(newBuffer, originalPtr, originalSize); return newBuffer;
return newBuffer; }
else
return NULL;
} }
//! Frees a memory block (concept Allocator) //! Frees a memory block (concept Allocator)
@ -229,15 +232,20 @@ private:
//! Creates a new chunk. //! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes. /*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/ */
void AddChunk(size_t capacity) { bool AddChunk(size_t capacity) {
if (!baseAllocator_) if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity)); if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
chunk->capacity = capacity; chunk->capacity = capacity;
chunk->size = 0; chunk->size = 0;
chunk->next = chunkHead_; chunk->next = chunkHead_;
chunkHead_ = chunk; chunkHead_ = chunk;
return true;
}
else
return false;
} }
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,7 @@
#define RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_
#include "stream.h" #include "stream.h"
#include "memorystream.h"
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -62,6 +63,34 @@ private:
Ch current_; Ch current_;
}; };
//! Specialized for UTF8 MemoryStream.
template <>
class EncodedInputStream<UTF8<>, MemoryStream> {
public:
typedef UTF8<>::Ch Ch;
EncodedInputStream(MemoryStream& is) : is_(is) {
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
}
Ch Peek() const { return is_.Peek(); }
Ch Take() { return is_.Take(); }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) {}
void Flush() {}
Ch* PutBegin() { return 0; }
size_t PutEnd(Ch*) { return 0; }
MemoryStream& is_;
private:
EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
};
//! Output byte stream wrapper with statically bound encoding. //! Output byte stream wrapper with statically bound encoding.
/*! /*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.

View file

@ -154,7 +154,11 @@ struct UTF8 {
} }
unsigned char type = GetRange(static_cast<unsigned char>(c)); unsigned char type = GetRange(static_cast<unsigned char>(c));
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c); if (type >= 32) {
*codepoint = 0;
} else {
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
}
bool result = true; bool result = true;
switch (type) { switch (type) {
case 2: TAIL(); return result; case 2: TAIL(); return result;

View file

@ -38,7 +38,7 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");

View file

@ -91,9 +91,14 @@ typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
// writer.h // writer.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator> template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class Writer; class Writer;
// prettywriter.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class PrettyWriter;
// document.h // document.h
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>

0
ext/rapidjson/internal/biginteger.h Executable file → Normal file
View file

View file

@ -41,7 +41,7 @@ RAPIDJSON_DIAG_OFF(padded)
#endif #endif
struct DiyFp { struct DiyFp {
DiyFp() {} DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}

View file

@ -29,6 +29,7 @@ namespace internal {
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
#endif #endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
@ -101,7 +102,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
kappa--; kappa--;
if (p2 < delta) { if (p2 < delta) {
*K += kappa; *K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]); int index = -static_cast<int>(kappa);
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
return; return;
} }
} }
@ -145,10 +147,10 @@ inline char* WriteExponent(int K, char* buffer) {
return buffer; return buffer;
} }
inline char* Prettify(char* buffer, int length, int k) { inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21) { if (0 <= k && kk <= 21) {
// 1234e7 -> 12340000000 // 1234e7 -> 12340000000
for (int i = length; i < kk; i++) for (int i = length; i < kk; i++)
buffer[i] = '0'; buffer[i] = '0';
@ -160,7 +162,16 @@ inline char* Prettify(char* buffer, int length, int k) {
// 1234e-2 -> 12.34 // 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.'; buffer[kk] = '.';
return &buffer[length + 1]; if (0 > k + maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[kk + 2]; // Reserve one zero
}
else
return &buffer[length + 1];
} }
else if (-6 < kk && kk <= 0) { else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234 // 1234e-6 -> 0.001234
@ -170,7 +181,23 @@ inline char* Prettify(char* buffer, int length, int k) {
buffer[1] = '.'; buffer[1] = '.';
for (int i = 2; i < offset; i++) for (int i = 2; i < offset; i++)
buffer[i] = '0'; buffer[i] = '0';
return &buffer[length + offset]; if (length - kk > maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = maxDecimalPlaces + 1; i > 2; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[3]; // Reserve one zero
}
else
return &buffer[length + offset];
}
else if (kk < -maxDecimalPlaces) {
// Truncate to zero
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
} }
else if (length == 1) { else if (length == 1) {
// 1e30 // 1e30
@ -186,7 +213,8 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
} }
inline char* dtoa(double value, char* buffer) { inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
Double d(value); Double d(value);
if (d.IsZero()) { if (d.IsZero()) {
if (d.Sign()) if (d.Sign())
@ -203,7 +231,7 @@ inline char* dtoa(double value, char* buffer) {
} }
int length, K; int length, K;
Grisu2(value, buffer, &length, &K); Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K); return Prettify(buffer, length, K, maxDecimalPlaces);
} }
} }

View file

@ -40,6 +40,7 @@ public:
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }

View file

@ -31,6 +31,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
#ifndef RAPIDJSON_REGEX_VERBOSE #ifndef RAPIDJSON_REGEX_VERBOSE
#define RAPIDJSON_REGEX_VERBOSE 0 #define RAPIDJSON_REGEX_VERBOSE 0
#endif #endif
@ -38,12 +43,40 @@ RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
///////////////////////////////////////////////////////////////////////////////
// DecodedStream
template <typename SourceStream, typename Encoding>
class DecodedStream {
public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
unsigned Peek() { return codepoint_; }
unsigned Take() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode();
return c;
}
private:
void Decode() {
if (!Encoding::Decode(ss_, &codepoint_))
codepoint_ = 0;
}
SourceStream& ss_;
unsigned codepoint_;
};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericRegex // GenericRegex
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0); static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator>
class GenericRegexSearch;
//! Regular expression engine with subset of ECMAscript grammar. //! Regular expression engine with subset of ECMAscript grammar.
/*! /*!
Supported regular expression syntax: Supported regular expression syntax:
@ -79,45 +112,25 @@ static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator = CrtAllocator> template <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex { class GenericRegex {
public: public:
typedef Encoding EncodingType;
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
template <typename, typename> friend class GenericRegexSearch;
GenericRegex(const Ch* source, Allocator* allocator = 0) : GenericRegex(const Ch* source, Allocator* allocator = 0) :
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() anchorBegin_(), anchorEnd_()
{ {
GenericStringStream<Encoding> ss(source); GenericStringStream<Encoding> ss(source);
DecodedStream<GenericStringStream<Encoding> > ds(ss); DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
Parse(ds); Parse(ds);
} }
~GenericRegex() { ~GenericRegex() {}
Allocator::Free(stateSet_);
}
bool IsValid() const { bool IsValid() const {
return root_ != kRegexInvalidState; return root_ != kRegexInvalidState;
} }
template <typename InputStream>
bool Match(InputStream& is) const {
return SearchWithAnchoring(is, true, true);
}
bool Match(const Ch* s) const {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) const {
return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
}
bool Search(const Ch* s) const {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private: private:
enum Operator { enum Operator {
kZeroOrOne, kZeroOrOne,
@ -152,28 +165,6 @@ private:
SizeType minIndex; SizeType minIndex;
}; };
template <typename SourceStream>
class DecodedStream {
public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
unsigned Peek() { return codepoint_; }
unsigned Take() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode();
return c;
}
private:
void Decode() {
if (!Encoding::Decode(ss_, &codepoint_))
codepoint_ = 0;
}
SourceStream& ss_;
unsigned codepoint_;
};
State& GetState(SizeType index) { State& GetState(SizeType index) {
RAPIDJSON_ASSERT(index < stateCount_); RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index]; return states_.template Bottom<State>()[index];
@ -195,7 +186,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
void Parse(DecodedStream<InputStream>& ds) { void Parse(DecodedStream<InputStream, Encoding>& ds) {
Allocator allocator; Allocator allocator;
Stack<Allocator> operandStack(&allocator, 256); // Frag Stack<Allocator> operandStack(&allocator, 256); // Frag
Stack<Allocator> operatorStack(&allocator, 256); // Operator Stack<Allocator> operatorStack(&allocator, 256); // Operator
@ -256,13 +247,13 @@ private:
case '{': case '{':
{ {
unsigned n, m; unsigned n, m;
if (!ParseUnsigned(ds, &n) || n == 0) if (!ParseUnsigned(ds, &n))
return; return;
if (ds.Peek() == ',') { if (ds.Peek() == ',') {
ds.Take(); ds.Take();
if (ds.Peek() == '}') if (ds.Peek() == '}')
m = 0; m = kInfinityQuantifier;
else if (!ParseUnsigned(ds, &m) || m < n) else if (!ParseUnsigned(ds, &m) || m < n)
return; return;
} }
@ -322,14 +313,6 @@ private:
printf("\n"); printf("\n");
#endif #endif
} }
// Preallocate buffer for SearchWithAnchoring()
RAPIDJSON_ASSERT(stateSet_ == 0);
if (stateCount_ > 0) {
stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(stateCount_);
state1_.template Reserve<SizeType>(stateCount_);
}
} }
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
@ -370,14 +353,14 @@ private:
bool Eval(Stack<Allocator>& operandStack, Operator op) { bool Eval(Stack<Allocator>& operandStack, Operator op) {
switch (op) { switch (op) {
case kConcatenation: case kConcatenation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) { RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
{
Frag e2 = *operandStack.template Pop<Frag>(1); Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1); Frag e1 = *operandStack.template Pop<Frag>(1);
Patch(e1.out, e2.start); Patch(e1.out, e2.start);
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
return true;
} }
return false; return true;
case kAlternation: case kAlternation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) { if (operandStack.GetSize() >= sizeof(Frag) * 2) {
@ -408,7 +391,8 @@ private:
} }
return false; return false;
case kOneOrMore: default:
RAPIDJSON_ASSERT(op == kOneOrMore);
if (operandStack.GetSize() >= sizeof(Frag)) { if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1); Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0); SizeType s = NewState(kRegexInvalidState, e.start, 0);
@ -417,22 +401,32 @@ private:
return true; return true;
} }
return false; return false;
default:
return false;
} }
} }
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) { bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
RAPIDJSON_ASSERT(n > 0); RAPIDJSON_ASSERT(n <= m);
RAPIDJSON_ASSERT(m == 0 || n <= m); // m == 0 means infinity RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
if (operandStack.GetSize() < sizeof(Frag))
return false; if (n == 0) {
if (m == 0) // a{0} not support
return false;
else if (m == kInfinityQuantifier)
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
else {
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
for (unsigned i = 0; i < m - 1; i++)
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
for (unsigned i = 0; i < m - 1; i++)
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
}
return true;
}
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
CloneTopOperand(operandStack); CloneTopOperand(operandStack);
if (m == 0) if (m == kInfinityQuantifier)
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
else if (m > n) { else if (m > n) {
CloneTopOperand(operandStack); // a{3,5} -> a a a a CloneTopOperand(operandStack); // a{3,5} -> a a a a
@ -452,23 +446,25 @@ private:
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
void CloneTopOperand(Stack<Allocator>& operandStack) { void CloneTopOperand(Stack<Allocator>& operandStack) {
const Frag *src = operandStack.template Top<Frag>(); const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
SizeType count = stateCount_ - src->minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
State* s = states_.template Push<State>(count); State* s = states_.template Push<State>(count);
memcpy(s, &GetState(src->minIndex), count * sizeof(State)); memcpy(s, &GetState(src.minIndex), count * sizeof(State));
for (SizeType j = 0; j < count; j++) { for (SizeType j = 0; j < count; j++) {
if (s[j].out != kRegexInvalidState) if (s[j].out != kRegexInvalidState)
s[j].out += count; s[j].out += count;
if (s[j].out1 != kRegexInvalidState) if (s[j].out1 != kRegexInvalidState)
s[j].out1 += count; s[j].out1 += count;
} }
*operandStack.template Push<Frag>() = Frag(src->start + count, src->out + count, src->minIndex + count); *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
stateCount_ += count; stateCount_ += count;
} }
template <typename InputStream> template <typename InputStream>
bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) { bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
unsigned r = 0; unsigned r = 0;
if (ds.Peek() < '0' || ds.Peek() > '9')
return false;
while (ds.Peek() >= '0' && ds.Peek() <= '9') { while (ds.Peek() >= '0' && ds.Peek() <= '9') {
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
return false; // overflow return false; // overflow
@ -479,7 +475,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) { bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
bool isBegin = true; bool isBegin = true;
bool negate = false; bool negate = false;
int step = 0; int step = 0;
@ -557,7 +553,7 @@ private:
} }
template <typename InputStream> template <typename InputStream>
bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) { bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
unsigned codepoint; unsigned codepoint;
switch (codepoint = ds.Take()) { switch (codepoint = ds.Take()) {
case '^': case '^':
@ -585,34 +581,93 @@ private:
} }
} }
Stack<Allocator> states_;
Stack<Allocator> ranges_;
SizeType root_;
SizeType stateCount_;
SizeType rangeCount_;
static const unsigned kInfinityQuantifier = ~0u;
// For SearchWithAnchoring()
bool anchorBegin_;
bool anchorEnd_;
};
template <typename RegexType, typename Allocator = CrtAllocator>
class GenericRegexSearch {
public:
typedef typename RegexType::EncodingType Encoding;
typedef typename Encoding::Ch Ch;
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
regex_(regex), allocator_(allocator), ownAllocator_(0),
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
{
RAPIDJSON_ASSERT(regex_.IsValid());
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(regex_.stateCount_);
state1_.template Reserve<SizeType>(regex_.stateCount_);
}
~GenericRegexSearch() {
Allocator::Free(stateSet_);
RAPIDJSON_DELETE(ownAllocator_);
}
template <typename InputStream> template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { bool Match(InputStream& is) {
RAPIDJSON_ASSERT(IsValid()); return SearchWithAnchoring(is, true, true);
DecodedStream<InputStream> ds(is); }
bool Match(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) {
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
}
bool Search(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private:
typedef typename RegexType::State State;
typedef typename RegexType::Range Range;
template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
DecodedStream<InputStream, Encoding> ds(is);
state0_.Clear(); state0_.Clear();
Stack<Allocator> *current = &state0_, *next = &state1_; Stack<Allocator> *current = &state0_, *next = &state1_;
const size_t stateSetSize = GetStateSetSize(); const size_t stateSetSize = GetStateSetSize();
std::memset(stateSet_, 0, stateSetSize); std::memset(stateSet_, 0, stateSetSize);
bool matched = AddState(*current, root_); bool matched = AddState(*current, regex_.root_);
unsigned codepoint; unsigned codepoint;
while (!current->Empty() && (codepoint = ds.Take()) != 0) { while (!current->Empty() && (codepoint = ds.Take()) != 0) {
std::memset(stateSet_, 0, stateSetSize); std::memset(stateSet_, 0, stateSetSize);
next->Clear(); next->Clear();
matched = false; matched = false;
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) { for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
const State& sr = GetState(*s); const State& sr = regex_.GetState(*s);
if (sr.codepoint == codepoint || if (sr.codepoint == codepoint ||
sr.codepoint == kAnyCharacterClass || sr.codepoint == RegexType::kAnyCharacterClass ||
(sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
{ {
matched = AddState(*next, sr.out) || matched; matched = AddState(*next, sr.out) || matched;
if (!anchorEnd && matched) if (!anchorEnd && matched)
return true; return true;
} }
if (!anchorBegin) if (!anchorBegin)
AddState(*next, root_); AddState(*next, regex_.root_);
} }
internal::Swap(current, next); internal::Swap(current, next);
} }
@ -621,15 +676,14 @@ private:
} }
size_t GetStateSetSize() const { size_t GetStateSetSize() const {
return (stateCount_ + 31) / 32 * 4; return (regex_.stateCount_ + 31) / 32 * 4;
} }
// Return whether the added states is a match state // Return whether the added states is a match state
bool AddState(Stack<Allocator>& l, SizeType index) const { bool AddState(Stack<Allocator>& l, SizeType index) {
if (index == kRegexInvalidState) RAPIDJSON_ASSERT(index != kRegexInvalidState);
return true;
const State& s = GetState(index); const State& s = regex_.GetState(index);
if (s.out1 != kRegexInvalidState) { // Split if (s.out1 != kRegexInvalidState) { // Split
bool matched = AddState(l, s.out); bool matched = AddState(l, s.out);
return AddState(l, s.out1) || matched; return AddState(l, s.out1) || matched;
@ -642,31 +696,26 @@ private:
} }
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
while (rangeIndex != kRegexInvalidRange) { while (rangeIndex != kRegexInvalidRange) {
const Range& r = GetRange(rangeIndex); const Range& r = regex_.GetRange(rangeIndex);
if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
return yes; return yes;
rangeIndex = r.next; rangeIndex = r.next;
} }
return !yes; return !yes;
} }
Stack<Allocator> states_; const RegexType& regex_;
Stack<Allocator> ranges_; Allocator* allocator_;
SizeType root_; Allocator* ownAllocator_;
SizeType stateCount_; Stack<Allocator> state0_;
SizeType rangeCount_; Stack<Allocator> state1_;
uint32_t* stateSet_;
// For SearchWithAnchoring()
uint32_t* stateSet_; // allocated by states_.GetAllocator()
mutable Stack<Allocator> state0_;
mutable Stack<Allocator> state1_;
bool anchorBegin_;
bool anchorEnd_;
}; };
typedef GenericRegex<UTF8<> > Regex; typedef GenericRegex<UTF8<> > Regex;
typedef GenericRegexSearch<Regex> RegexSearch;
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
@ -675,4 +724,8 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_REGEX_H_ #endif // RAPIDJSON_INTERNAL_REGEX_H_

View file

@ -28,6 +28,7 @@ namespace internal {
*/ */
template <typename Ch> template <typename Ch>
inline SizeType StrLen(const Ch* s) { inline SizeType StrLen(const Ch* s) {
RAPIDJSON_ASSERT(s != 0);
const Ch* p = s; const Ch* p = s;
while (*p) ++p; while (*p) ++p;
return SizeType(p - s); return SizeType(p - s);
@ -36,6 +37,8 @@ inline SizeType StrLen(const Ch* s) {
//! Returns number of code points in a encoded string. //! Returns number of code points in a encoded string.
template<typename Encoding> template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
RAPIDJSON_ASSERT(s != 0);
RAPIDJSON_ASSERT(outCount != 0);
GenericStringStream<Encoding> is(s); GenericStringStream<Encoding> is(s);
const typename Encoding::Ch* end = s + length; const typename Encoding::Ch* end = s + length;
SizeType count = 0; SizeType count = 0;

View file

@ -142,7 +142,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
size_t remaining = length - i; size_t remaining = length - i;
const unsigned kUlpShift = 3; const unsigned kUlpShift = 3;
const unsigned kUlp = 1 << kUlpShift; const unsigned kUlp = 1 << kUlpShift;
int error = (remaining == 0) ? 0 : kUlp / 2; int64_t error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0); DiyFp v(significand, 0);
v = v.Normalize(); v = v.Normalize();

View file

@ -0,0 +1,115 @@
// 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_ISTREAMWRAPPER_H_
#define RAPIDJSON_ISTREAMWRAPPER_H_
#include "stream.h"
#include <iosfwd>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
/*!
The classes can be wrapped including but not limited to:
- \c std::istringstream
- \c std::stringstream
- \c std::wistringstream
- \c std::wstringstream
- \c std::ifstream
- \c std::fstream
- \c std::wifstream
- \c std::wfstream
\tparam StreamType Class derived from \c std::basic_istream.
*/
template <typename StreamType>
class BasicIStreamWrapper {
public:
typedef typename StreamType::char_type Ch;
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
Ch Peek() const {
typename StreamType::int_type c = stream_.peek();
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
}
Ch Take() {
typename StreamType::int_type c = stream_.get();
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
count_++;
return static_cast<Ch>(c);
}
else
return '\0';
}
// tellg() may return -1 when failed. So we count by ourself.
size_t Tell() const { return count_; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
int i;
bool hasError = false;
for (i = 0; i < 4; ++i) {
typename StreamType::int_type c = stream_.get();
if (c == StreamType::traits_type::eof()) {
hasError = true;
stream_.clear();
break;
}
peekBuffer_[i] = static_cast<Ch>(c);
}
for (--i; i >= 0; --i)
stream_.putback(peekBuffer_[i]);
return !hasError ? peekBuffer_ : 0;
}
private:
BasicIStreamWrapper(const BasicIStreamWrapper&);
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
StreamType& stream_;
size_t count_; //!< Number of characters read. Note:
mutable Ch peekBuffer_[4];
};
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ISTREAMWRAPPER_H_

View file

@ -42,8 +42,8 @@ struct MemoryStream {
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return (src_ == end_) ? '\0' : *src_; } Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; } Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); } size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }

View file

@ -0,0 +1,81 @@
// 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_OSTREAMWRAPPER_H_
#define RAPIDJSON_OSTREAMWRAPPER_H_
#include "stream.h"
#include <iosfwd>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
/*!
The classes can be wrapped including but not limited to:
- \c std::ostringstream
- \c std::stringstream
- \c std::wpstringstream
- \c std::wstringstream
- \c std::ifstream
- \c std::fstream
- \c std::wofstream
- \c std::wfstream
\tparam StreamType Class derived from \c std::basic_ostream.
*/
template <typename StreamType>
class BasicOStreamWrapper {
public:
typedef typename StreamType::char_type Ch;
BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
void Put(Ch c) {
stream_.put(c);
}
void Flush() {
stream_.flush();
}
// Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
private:
BasicOStreamWrapper(const BasicOStreamWrapper&);
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
StreamType& stream_;
};
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_OSTREAMWRAPPER_H_

View file

@ -23,6 +23,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch-enum)
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
@ -460,9 +465,18 @@ public:
//! Query a value in a subtree. //! Query a value in a subtree.
/*! /*!
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
\return Pointer to the value if it can be resolved. Otherwise null. \return Pointer to the value if it can be resolved. Otherwise null.
\note
There are only 3 situations when a value cannot be resolved:
1. A value in the path is not an array nor object.
2. An object value does not contain the token.
3. A token is out of range of an array value.
Use unresolvedTokenIndex to retrieve the token index.
*/ */
ValueType* Get(ValueType& root) const { ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
RAPIDJSON_ASSERT(IsValid()); RAPIDJSON_ASSERT(IsValid());
ValueType* v = &root; ValueType* v = &root;
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
@ -471,18 +485,23 @@ public:
{ {
typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
if (m == v->MemberEnd()) if (m == v->MemberEnd())
return 0; break;
v = &m->value; v = &m->value;
} }
break; continue;
case kArrayType: case kArrayType:
if (t->index == kPointerInvalidIndex || t->index >= v->Size()) if (t->index == kPointerInvalidIndex || t->index >= v->Size())
return 0; break;
v = &((*v)[t->index]); v = &((*v)[t->index]);
break; continue;
default: default:
return 0; break;
} }
// Error: unresolved token
if (unresolvedTokenIndex)
*unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
return 0;
} }
return v; return v;
} }
@ -492,7 +511,9 @@ public:
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
\return Pointer to the value if it can be resolved. Otherwise null. \return Pointer to the value if it can be resolved. Otherwise null.
*/ */
const ValueType* Get(const ValueType& root) const { return Get(const_cast<ValueType&>(root)); } const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
}
//@} //@}
@ -746,8 +767,12 @@ private:
tokenCount_ = rhs.tokenCount_ + extraToken; tokenCount_ = rhs.tokenCount_ + extraToken;
tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); if (rhs.tokenCount_ > 0) {
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
}
if (nameBufferSize > 0) {
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
}
// Adjust pointers to name buffer // Adjust pointers to name buffer
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
@ -971,11 +996,11 @@ private:
src_++; src_++;
Ch c = 0; Ch c = 0;
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
c <<= 4; c = static_cast<Ch>(c << 4);
Ch h = *src_; Ch h = *src_;
if (h >= '0' && h <= '9') c += h - '0'; if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
else if (h >= 'A' && h <= 'F') c += h - 'A' + 10; else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
else if (h >= 'a' && h <= 'f') c += h - 'a' + 10; else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
else { else {
valid_ = false; valid_ = false;
return 0; return 0;
@ -1053,23 +1078,23 @@ typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, c
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
template <typename T> template <typename T>
typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) { typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
return pointer.Get(root); return pointer.Get(root, unresolvedTokenIndex);
} }
template <typename T> template <typename T>
const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer) { const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
return pointer.Get(root); return pointer.Get(root, unresolvedTokenIndex);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) { typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
return GenericPointer<typename T::ValueType>(source, N - 1).Get(root); return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) { const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
return GenericPointer<typename T::ValueType>(source, N - 1).Get(root); return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -1326,4 +1351,8 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_POINTER_H_ #endif // RAPIDJSON_POINTER_H_

View file

@ -22,8 +22,21 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#if defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
//! Combination of PrettyWriter format flags.
/*! \see PrettyWriter::SetFormatOptions
*/
enum PrettyFormatOptions {
kFormatDefault = 0, //!< Default pretty formatting.
kFormatSingleLineArray = 1 //!< Format arrays on a single line.
};
//! Writer with indentation and spacing. //! Writer with indentation and spacing.
/*! /*!
\tparam OutputStream Type of ouptut os. \tparam OutputStream Type of ouptut os.
@ -31,8 +44,8 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam TargetEncoding Encoding of output stream. \tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack. \tparam StackAllocator Type of allocator for allocating memory of stack.
*/ */
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> { class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
public: public:
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base; typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
typedef typename Base::Ch Ch; typedef typename Base::Ch Ch;
@ -42,8 +55,17 @@ public:
\param allocator User supplied allocator. If it is null, it will create a private one. \param allocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack. \param levelDepth Initial capacity of stack.
*/ */
PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
PrettyWriter(PrettyWriter&& rhs) :
Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
#endif
//! Set custom indentation. //! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
@ -57,6 +79,14 @@ public:
return *this; return *this;
} }
//! Set pretty writer formatting options.
/*! \param options Formatting options.
*/
PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
formatOptions_ = options;
return *this;
}
/*! @name Implementation of Handler /*! @name Implementation of Handler
\see Handler \see Handler
*/ */
@ -70,7 +100,15 @@ public:
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0);
(void)copy;
PrettyPrefix(kNumberType);
return Base::WriteString(str, length);
}
bool String(const Ch* str, SizeType length, bool copy = false) { bool String(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0);
(void)copy; (void)copy;
PrettyPrefix(kStringType); PrettyPrefix(kStringType);
return Base::WriteString(str, length); return Base::WriteString(str, length);
@ -90,6 +128,12 @@ public:
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
#if RAPIDJSON_HAS_STDSTRING
bool Key(const std::basic_string<Ch>& str) {
return Key(str.data(), SizeType(str.size()));
}
#endif
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0) {
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
@ -120,7 +164,7 @@ public:
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray); RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
@ -142,6 +186,22 @@ public:
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
//@} //@}
//! Write a raw JSON value.
/*!
For user to write a stringified JSON as a value.
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
\param length Length of the json.
\param type Type of the root of json.
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
*/
bool RawValue(const Ch* json, size_t length, Type type) {
RAPIDJSON_ASSERT(json != 0);
PrettyPrefix(type);
return Base::WriteRawValue(json, length);
}
protected: protected:
void PrettyPrefix(Type type) { void PrettyPrefix(Type type) {
(void)type; (void)type;
@ -151,11 +211,14 @@ protected:
if (level->inArray) { if (level->inArray) {
if (level->valueCount > 0) { if (level->valueCount > 0) {
Base::os_->Put(','); // add comma if it is not the first element in array Base::os_->Put(','); // add comma if it is not the first element in array
Base::os_->Put('\n'); if (formatOptions_ & kFormatSingleLineArray)
Base::os_->Put(' ');
} }
else
if (!(formatOptions_ & kFormatSingleLineArray)) {
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
}
} }
else { // in object else { // in object
if (level->valueCount > 0) { if (level->valueCount > 0) {
@ -191,6 +254,7 @@ protected:
Ch indentChar_; Ch indentChar_;
unsigned indentCharCount_; unsigned indentCharCount_;
PrettyFormatOptions formatOptions_;
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
@ -200,6 +264,10 @@ private:
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif

View file

@ -68,8 +68,8 @@
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format. \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
*/ */
#define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MAJOR_VERSION 1
#define RAPIDJSON_MINOR_VERSION 0 #define RAPIDJSON_MINOR_VERSION 1
#define RAPIDJSON_PATCH_VERSION 2 #define RAPIDJSON_PATCH_VERSION 0
#define RAPIDJSON_VERSION_STRING \ #define RAPIDJSON_VERSION_STRING \
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
@ -159,7 +159,7 @@
*/ */
#ifndef RAPIDJSON_NO_INT64DEFINE #ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#ifdef _MSC_VER #if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
#include "msinttypes/stdint.h" #include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h" #include "msinttypes/inttypes.h"
#else #else
@ -250,7 +250,7 @@
//! Whether using 64-bit architecture //! Whether using 64-bit architecture
#ifndef RAPIDJSON_64BIT #ifndef RAPIDJSON_64BIT
#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__) #if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
#define RAPIDJSON_64BIT 1 #define RAPIDJSON_64BIT 1
#else #else
#define RAPIDJSON_64BIT 0 #define RAPIDJSON_64BIT 0
@ -265,7 +265,8 @@
\param x pointer to align \param x pointer to align
Some machines require strict data alignment. Currently the default uses 4 bytes Some machines require strict data alignment. Currently the default uses 4 bytes
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro. alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
User can customize by defining the RAPIDJSON_ALIGN function macro.
*/ */
#ifndef RAPIDJSON_ALIGN #ifndef RAPIDJSON_ALIGN
#if RAPIDJSON_64BIT == 1 #if RAPIDJSON_64BIT == 1
@ -288,6 +289,36 @@
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32)) #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#endif #endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
//! Use only lower 48-bit address for some pointers.
/*!
\ingroup RAPIDJSON_CONFIG
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
The higher 16-bit can be used for storing other data.
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
*/
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
#else
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
#endif
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
#if RAPIDJSON_64BIT != 1
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
#endif
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
#else
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
#define RAPIDJSON_GETPOINTER(type, p) (p)
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
@ -421,7 +452,7 @@ RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) #define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
#else #else
#define RAPIDJSON_LIKELY(x) x #define RAPIDJSON_LIKELY(x) (x)
#endif #endif
#endif #endif
@ -434,7 +465,7 @@ RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else #else
#define RAPIDJSON_UNLIKELY(x) x #define RAPIDJSON_UNLIKELY(x) (x)
#endif #endif
#endif #endif
@ -498,8 +529,12 @@ RAPIDJSON_NAMESPACE_END
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if defined(__clang__) #if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \ #if __has_feature(cxx_rvalue_references) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
#endif
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1600) (defined(_MSC_VER) && _MSC_VER >= 1600)
@ -530,6 +565,17 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
#endif #endif
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1700)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
#else
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
#endif
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
//!@endcond //!@endcond
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View file

@ -19,9 +19,11 @@
#include "allocators.h" #include "allocators.h"
#include "stream.h" #include "stream.h"
#include "encodedstream.h"
#include "internal/meta.h" #include "internal/meta.h"
#include "internal/stack.h" #include "internal/stack.h"
#include "internal/strtod.h" #include "internal/strtod.h"
#include <limits>
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
@ -41,6 +43,7 @@ RAPIDJSON_DIAG_OFF(4702) // unreachable code
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(old-style-cast)
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch-enum)
#endif #endif
@ -147,6 +150,9 @@ enum ParseFlag {
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). kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. 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 kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
}; };
@ -168,6 +174,8 @@ concept Handler {
bool Int64(int64_t i); bool Int64(int64_t i);
bool Uint64(uint64_t i); bool Uint64(uint64_t i);
bool Double(double d); bool Double(double d);
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
bool RawNumber(const Ch* str, SizeType length, bool copy);
bool String(const Ch* str, SizeType length, bool copy); bool String(const Ch* str, SizeType length, bool copy);
bool StartObject(); bool StartObject();
bool Key(const Ch* str, SizeType length, bool copy); bool Key(const Ch* str, SizeType length, bool copy);
@ -198,6 +206,8 @@ struct BaseReaderHandler {
bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); } bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); } bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
bool Double(double) { return static_cast<Override&>(*this).Default(); } bool Double(double) { return static_cast<Override&>(*this).Default(); }
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (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 String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
bool StartObject() { return static_cast<Override&>(*this).Default(); } bool StartObject() { return static_cast<Override&>(*this).Default(); }
bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
@ -255,10 +265,17 @@ void SkipWhitespace(InputStream& is) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
InputStream& s(copy.s); InputStream& s(copy.s);
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') typename InputStream::Ch c;
while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
s.Take(); s.Take();
} }
inline const char* SkipWhitespace(const char* p, const char* end) {
while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
return p;
}
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
@ -295,6 +312,34 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
} }
} }
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) #elif defined(RAPIDJSON_SSE2)
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
@ -342,6 +387,44 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
} }
} }
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 #endif // RAPIDJSON_SSE2
#ifdef RAPIDJSON_SIMD #ifdef RAPIDJSON_SIMD
@ -354,6 +437,10 @@ template<> inline void SkipWhitespace(InsituStringStream& is) {
template<> inline void SkipWhitespace(StringStream& is) { template<> inline void SkipWhitespace(StringStream& is) {
is.src_ = SkipWhitespace_SIMD(is.src_); is.src_ = SkipWhitespace_SIMD(is.src_);
} }
template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
}
#endif // RAPIDJSON_SIMD #endif // RAPIDJSON_SIMD
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -474,28 +561,21 @@ private:
SkipWhitespace(is); SkipWhitespace(is);
if (parseFlags & kParseCommentsFlag) { if (parseFlags & kParseCommentsFlag) {
while (RAPIDJSON_UNLIKELY(is.Peek() == '/')) { while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
is.Take(); if (Consume(is, '*')) {
if (is.Peek() == '*') {
is.Take();
while (true) { while (true) {
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
else if (Consume(is, '*')) {
if (is.Take() == '*') { if (Consume(is, '/'))
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
if (is.Take() == '/')
break; break;
} }
else
is.Take();
} }
} }
else if (RAPIDJSON_LIKELY(is.Peek() == '/')) { else if (RAPIDJSON_LIKELY(Consume(is, '/')))
is.Take(); while (is.Peek() != '\0' && is.Take() != '\n');
while (is.Peek() != '\0' && is.Take() != '\n') { }
}
else else
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
@ -516,8 +596,7 @@ private:
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == '}') { if (Consume(is, '}')) {
is.Take();
if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
@ -533,7 +612,7 @@ private:
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (RAPIDJSON_UNLIKELY(is.Take() != ':')) if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
@ -547,18 +626,28 @@ private:
++memberCount; ++memberCount;
switch (is.Take()) { switch (is.Peek()) {
case ',': case ',':
is.Take();
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break; break;
case '}': case '}':
is.Take();
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
default: default:
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
break; }
if (parseFlags & kParseTrailingCommasFlag) {
if (is.Peek() == '}') {
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
is.Take();
return;
}
} }
} }
} }
@ -575,8 +664,7 @@ private:
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == ']') { if (Consume(is, ']')) {
is.Take();
if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
@ -590,18 +678,25 @@ private:
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
switch (is.Take()) { if (Consume(is, ',')) {
case ',': SkipWhitespaceAndComments<parseFlags>(is);
SkipWhitespaceAndComments<parseFlags>(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; }
break; else if (Consume(is, ']')) {
case ']': 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))) if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
is.Take();
return; return;
default: }
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
break;
} }
} }
} }
@ -611,12 +706,12 @@ private:
RAPIDJSON_ASSERT(is.Peek() == 'n'); RAPIDJSON_ASSERT(is.Peek() == 'n');
is.Take(); is.Take();
if (RAPIDJSON_LIKELY(is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')) { if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
if (RAPIDJSON_UNLIKELY(!handler.Null())) if (RAPIDJSON_UNLIKELY(!handler.Null()))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
} }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
@ -624,12 +719,12 @@ private:
RAPIDJSON_ASSERT(is.Peek() == 't'); RAPIDJSON_ASSERT(is.Peek() == 't');
is.Take(); is.Take();
if (RAPIDJSON_LIKELY(is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')) { if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
} }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
@ -637,20 +732,30 @@ private:
RAPIDJSON_ASSERT(is.Peek() == 'f'); RAPIDJSON_ASSERT(is.Peek() == 'f');
is.Take(); is.Take();
if (RAPIDJSON_LIKELY(is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')) { if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
}
template<typename InputStream>
RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename 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(). // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
template<typename InputStream> template<typename InputStream>
unsigned ParseHex4(InputStream& is) { unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
unsigned codepoint = 0; unsigned codepoint = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Ch c = is.Take(); Ch c = is.Peek();
codepoint <<= 4; codepoint <<= 4;
codepoint += static_cast<unsigned>(c); codepoint += static_cast<unsigned>(c);
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
@ -660,9 +765,10 @@ private:
else if (c >= 'a' && c <= 'f') else if (c >= 'a' && c <= 'f')
codepoint -= 'a' - 10; codepoint -= 'a' - 10;
else { else {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
} }
is.Take();
} }
return codepoint; return codepoint;
} }
@ -751,27 +857,31 @@ private:
Ch c = is.Peek(); Ch c = is.Peek();
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
is.Take(); is.Take();
Ch e = is.Take(); Ch e = is.Peek();
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) 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)])); os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
}
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
unsigned codepoint = ParseHex4(is); is.Take();
unsigned codepoint = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
// Handle UTF-16 surrogate pair // Handle UTF-16 surrogate pair
if (RAPIDJSON_UNLIKELY(is.Take() != '\\' || is.Take() != 'u')) if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
unsigned codepoint2 = ParseHex4(is); unsigned codepoint2 = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
} }
TEncoding::Encode(os, codepoint); TEncoding::Encode(os, codepoint);
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
} }
else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
is.Take(); is.Take();
@ -780,15 +890,16 @@ private:
} }
else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
if (c == '\0') if (c == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
else else
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
} }
else { else {
size_t offset = is.Tell();
if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
!Transcoder<SEncoding, TEncoding>::Validate(is, os) : !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
!Transcoder<SEncoding, TEncoding>::Transcode(is, os)))) !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
} }
} }
} }
@ -955,18 +1066,22 @@ private:
} }
#endif #endif
template<typename InputStream, bool backup> template<typename InputStream, bool backup, bool pushOnTake>
class NumberStream; class NumberStream;
template<typename InputStream> template<typename InputStream>
class NumberStream<InputStream, false> { class NumberStream<InputStream, false, false> {
public: public:
typedef typename InputStream::Ch Ch;
NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
~NumberStream() {} ~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
RAPIDJSON_FORCEINLINE void Push(char) {}
size_t Tell() { return is.Tell(); } size_t Tell() { return is.Tell(); }
size_t Length() { return 0; } size_t Length() { return 0; }
const char* Pop() { return 0; } const char* Pop() { return 0; }
@ -978,10 +1093,10 @@ private:
}; };
template<typename InputStream> template<typename InputStream>
class NumberStream<InputStream, true> : public NumberStream<InputStream, false> { class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
typedef NumberStream<InputStream, false> Base; typedef NumberStream<InputStream, false, false> Base;
public: public:
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {} NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
~NumberStream() {} ~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch TakePush() { RAPIDJSON_FORCEINLINE Ch TakePush() {
@ -989,6 +1104,10 @@ private:
return Base::is.Take(); return Base::is.Take();
} }
RAPIDJSON_FORCEINLINE void Push(char c) {
stackStream.Put(c);
}
size_t Length() { return stackStream.Length(); } size_t Length() { return stackStream.Length(); }
const char* Pop() { const char* Pop() {
@ -1000,17 +1119,32 @@ private:
StackStream<char> stackStream; 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> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) { void ParseNumber(InputStream& is, Handler& handler) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s); 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 // Parse minus
bool minus = false; bool minus = Consume(s, '-');
if (s.Peek() == '-') {
minus = true;
s.Take();
}
// Parse int: zero / ( digit1-9 *DIGIT ) // Parse int: zero / ( digit1-9 *DIGIT )
unsigned i = 0; unsigned i = 0;
@ -1049,12 +1183,26 @@ private:
significandDigit++; significandDigit++;
} }
} }
// Parse NaN or Infinity here
else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
useNanOrInf = true;
if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {
d = std::numeric_limits<double>::quiet_NaN();
}
else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && 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 else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
// Parse 64bit int // Parse 64bit int
bool useDouble = false; bool useDouble = false;
double d = 0.0;
if (use64bit) { if (use64bit) {
if (minus) if (minus)
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
@ -1084,7 +1232,7 @@ private:
if (useDouble) { if (useDouble) {
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
d = d * 10 + (s.TakePush() - '0'); d = d * 10 + (s.TakePush() - '0');
} }
} }
@ -1092,8 +1240,7 @@ private:
// Parse frac = decimal-point 1*DIGIT // Parse frac = decimal-point 1*DIGIT
int expFrac = 0; int expFrac = 0;
size_t decimalPosition; size_t decimalPosition;
if (s.Peek() == '.') { if (Consume(s, '.')) {
s.Take();
decimalPosition = s.Length(); decimalPosition = s.Length();
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
@ -1140,20 +1287,17 @@ private:
// Parse exp = e [ minus / plus ] 1*DIGIT // Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0; int exp = 0;
if (s.Peek() == 'e' || s.Peek() == 'E') { if (Consume(s, 'e') || Consume(s, 'E')) {
if (!useDouble) { if (!useDouble) {
d = static_cast<double>(use64bit ? i64 : i); d = static_cast<double>(use64bit ? i64 : i);
useDouble = true; useDouble = true;
} }
s.Take();
bool expMinus = false; bool expMinus = false;
if (s.Peek() == '+') if (Consume(s, '+'))
s.Take(); ;
else if (s.Peek() == '-') { else if (Consume(s, '-'))
s.Take();
expMinus = true; expMinus = true;
}
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
exp = static_cast<int>(s.Take() - '0'); exp = static_cast<int>(s.Take() - '0');
@ -1171,7 +1315,7 @@ private:
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
exp = exp * 10 + static_cast<int>(s.Take() - '0'); exp = exp * 10 + static_cast<int>(s.Take() - '0');
if (RAPIDJSON_UNLIKELY(exp > maxExp)) if (RAPIDJSON_UNLIKELY(exp > maxExp))
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
} }
} }
} }
@ -1184,34 +1328,63 @@ private:
// Finish parsing, call event according to the type of number. // Finish parsing, call event according to the type of number.
bool cont = true; bool cont = true;
size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
if (useDouble) { if (parseFlags & kParseNumbersAsStringsFlag) {
int p = exp + expFrac; if (parseFlags & kParseInsituFlag) {
if (parseFlags & kParseFullPrecisionFlag) s.Pop(); // Pop stack no matter if it will be used or not.
d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); typename InputStream::Ch* head = is.PutBegin();
else const size_t length = s.Tell() - startOffset;
d = internal::StrtodNormalPrecision(d, p); RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
// unable to insert the \0 character here, it will erase the comma after this number
cont = handler.Double(minus ? -d : d); const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
} cont = handler.RawNumber(str, SizeType(length), false);
else {
if (use64bit) {
if (minus)
cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
else
cont = handler.Uint64(i64);
} }
else { else {
if (minus) SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
cont = handler.Int(static_cast<int32_t>(~i + 1)); StringStream srcStream(s.Pop());
else StackStream<typename TargetEncoding::Ch> dstStream(stack_);
cont = handler.Uint(i); 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)) if (RAPIDJSON_UNLIKELY(!cont))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
} }
// Parse any JSON value // Parse any JSON value
@ -1396,7 +1569,7 @@ private:
IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Left bracket
IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Right bracket
IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Left curly bracket
IterativeParsingErrorState, // Right curly bracket IterativeParsingObjectFinishState, // Right curly bracket
IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Comma
IterativeParsingErrorState, // Colon IterativeParsingErrorState, // Colon
IterativeParsingMemberKeyState, // String IterativeParsingMemberKeyState, // String
@ -1442,7 +1615,7 @@ private:
// ElementDelimiter // ElementDelimiter
{ {
IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayInitialState, // Left bracket(push Element state)
IterativeParsingErrorState, // Right bracket IterativeParsingArrayFinishState, // Right bracket
IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Right curly bracket
IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Comma
@ -1544,6 +1717,11 @@ private:
case IterativeParsingObjectFinishState: 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. // Get member count.
SizeType c = *stack_.template Pop<SizeType>(1); SizeType c = *stack_.template Pop<SizeType>(1);
// If the object is not empty, count the last member. // If the object is not empty, count the last member.
@ -1569,6 +1747,11 @@ private:
case IterativeParsingArrayFinishState: 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. // Get element count.
SizeType c = *stack_.template Pop<SizeType>(1); SizeType c = *stack_.template Pop<SizeType>(1);
// If the array is not empty, count the last element. // If the array is not empty, count the last element.
@ -1628,8 +1811,10 @@ private:
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; case IterativeParsingKeyValueDelimiterState:
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; case IterativeParsingArrayInitialState:
case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
} }
} }

View file

@ -19,13 +19,6 @@
#include "pointer.h" #include "pointer.h"
#include <cmath> // abs, floor #include <cmath> // abs, floor
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(weak-vtables)
RAPIDJSON_DIAG_OFF(exit-time-destructors)
RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
#endif
#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
#else #else
@ -58,16 +51,23 @@ RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
#include "stringbuffer.h" #include "stringbuffer.h"
#endif #endif
#if defined(__GNUC__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
#if defined(__GNUC__)
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(weak-vtables)
RAPIDJSON_DIAG_OFF(exit-time-destructors)
RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
RAPIDJSON_DIAG_OFF(variadic-macros) RAPIDJSON_DIAG_OFF(variadic-macros)
#endif #endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -154,7 +154,6 @@ public:
virtual uint64_t GetHashCode(void* hasher) = 0; virtual uint64_t GetHashCode(void* hasher) = 0;
virtual void DestroryHasher(void* hasher) = 0; virtual void DestroryHasher(void* hasher) = 0;
virtual void* MallocState(size_t size) = 0; virtual void* MallocState(size_t size) = 0;
virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) = 0;
virtual void FreeState(void* p) = 0; virtual void FreeState(void* p) = 0;
}; };
@ -183,6 +182,11 @@ public:
return WriteNumber(n); return WriteNumber(n);
} }
bool RawNumber(const Ch* str, SizeType len, bool) {
WriteBuffer(kNumberType, str, len * sizeof(Ch));
return true;
}
bool String(const Ch* str, SizeType len, bool) { bool String(const Ch* str, SizeType len, bool) {
WriteBuffer(kStringType, str, len * sizeof(Ch)); WriteBuffer(kStringType, str, len * sizeof(Ch));
return true; return true;
@ -280,7 +284,7 @@ struct SchemaValidationContext {
patternPropertiesSchemas(), patternPropertiesSchemas(),
patternPropertiesSchemaCount(), patternPropertiesSchemaCount(),
valuePatternValidatorType(kPatternValidatorOnly), valuePatternValidatorType(kPatternValidatorOnly),
objectDependencies(), propertyExist(),
inArray(false), inArray(false),
valueUniqueness(false), valueUniqueness(false),
arrayUniqueness(false) arrayUniqueness(false)
@ -302,8 +306,8 @@ struct SchemaValidationContext {
} }
if (patternPropertiesSchemas) if (patternPropertiesSchemas)
factory.FreeState(patternPropertiesSchemas); factory.FreeState(patternPropertiesSchemas);
if (objectDependencies) if (propertyExist)
factory.FreeState(objectDependencies); factory.FreeState(propertyExist);
} }
SchemaValidatorFactoryType& factory; SchemaValidatorFactoryType& factory;
@ -320,9 +324,8 @@ struct SchemaValidationContext {
SizeType patternPropertiesSchemaCount; SizeType patternPropertiesSchemaCount;
PatternValidatorType valuePatternValidatorType; PatternValidatorType valuePatternValidatorType;
PatternValidatorType objectPatternValidatorType; PatternValidatorType objectPatternValidatorType;
SizeType objectRequiredCount;
SizeType arrayElementIndex; SizeType arrayElementIndex;
bool* objectDependencies; bool* propertyExist;
bool inArray; bool inArray;
bool valueUniqueness; bool valueUniqueness;
bool arrayUniqueness; bool arrayUniqueness;
@ -356,11 +359,11 @@ public:
patternProperties_(), patternProperties_(),
patternPropertyCount_(), patternPropertyCount_(),
propertyCount_(), propertyCount_(),
requiredCount_(),
minProperties_(), minProperties_(),
maxProperties_(SizeType(~0)), maxProperties_(SizeType(~0)),
additionalProperties_(true), additionalProperties_(true),
hasDependencies_(), hasDependencies_(),
hasRequired_(),
hasSchemaDependencies_(), hasSchemaDependencies_(),
additionalItemsSchema_(), additionalItemsSchema_(),
itemsList_(), itemsList_(),
@ -405,9 +408,11 @@ public:
} }
} }
AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); if (schemaDocument) {
AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
}
if (const ValueType* v = GetMember(value, GetNotString())) { if (const ValueType* v = GetMember(value, GetNotString())) {
schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document); schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
@ -481,7 +486,7 @@ public:
SizeType index; SizeType index;
if (FindPropertyIndex(*itr, &index)) { if (FindPropertyIndex(*itr, &index)) {
properties_[index].required = true; properties_[index].required = true;
requiredCount_++; hasRequired_ = true;
} }
} }
@ -570,7 +575,9 @@ public:
} }
~Schema() { ~Schema() {
allocator_->Free(enum_); if (allocator_) {
allocator_->Free(enum_);
}
if (properties_) { if (properties_) {
for (SizeType i = 0; i < propertyCount_; i++) for (SizeType i = 0; i < propertyCount_; i++)
properties_[i].~Property(); properties_[i].~Property();
@ -758,10 +765,9 @@ public:
if (!(type_ & (1 << kObjectSchemaType))) if (!(type_ & (1 << kObjectSchemaType)))
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
context.objectRequiredCount = 0; if (hasDependencies_ || hasRequired_) {
if (hasDependencies_) { context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
context.objectDependencies = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_)); std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_);
} }
if (patternProperties_) { // pre-allocate schema array if (patternProperties_) { // pre-allocate schema array
@ -792,11 +798,8 @@ public:
else else
context.valueSchema = properties_[index].schema; context.valueSchema = properties_[index].schema;
if (properties_[index].required) if (context.propertyExist)
context.objectRequiredCount++; context.propertyExist[index] = true;
if (hasDependencies_)
context.objectDependencies[index] = true;
return true; return true;
} }
@ -823,8 +826,11 @@ public:
} }
bool EndObject(Context& context, SizeType memberCount) const { bool EndObject(Context& context, SizeType memberCount) const {
if (context.objectRequiredCount != requiredCount_) if (hasRequired_)
RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); for (SizeType index = 0; index < propertyCount_; index++)
if (properties_[index].required)
if (!context.propertyExist[index])
RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
if (memberCount < minProperties_) if (memberCount < minProperties_)
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
@ -834,10 +840,10 @@ public:
if (hasDependencies_) { if (hasDependencies_) {
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
if (context.objectDependencies[sourceIndex]) { if (context.propertyExist[sourceIndex]) {
if (properties_[sourceIndex].dependencies) { if (properties_[sourceIndex].dependencies) {
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex]) if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
} }
else if (properties_[sourceIndex].dependenciesSchema) else if (properties_[sourceIndex].dependenciesSchema)
@ -996,6 +1002,7 @@ private:
RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
if (!r->IsValid()) { if (!r->IsValid()) {
r->~RegexType(); r->~RegexType();
AllocatorType::Free(r);
r = 0; r = 0;
} }
return r; return r;
@ -1004,7 +1011,8 @@ private:
} }
static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
return pattern->Search(str); GenericRegexSearch<RegexType> rs(*pattern);
return rs.Search(str);
} }
#elif RAPIDJSON_SCHEMA_USE_STDREGEX #elif RAPIDJSON_SCHEMA_USE_STDREGEX
template <typename ValueType> template <typename ValueType>
@ -1098,6 +1106,9 @@ private:
if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
} }
else if (minimum_.IsUint64()) {
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
}
else if (!CheckDoubleMinimum(context, static_cast<double>(i))) else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false; return false;
} }
@ -1107,6 +1118,8 @@ private:
if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
} }
else if (maximum_.IsUint64())
/* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
else if (!CheckDoubleMaximum(context, static_cast<double>(i))) else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false; return false;
} }
@ -1132,6 +1145,8 @@ private:
if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
} }
else if (minimum_.IsInt64())
/* do nothing */; // i >= 0 > minimum.Getint64()
else if (!CheckDoubleMinimum(context, static_cast<double>(i))) else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false; return false;
} }
@ -1141,6 +1156,8 @@ private:
if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
} }
else if (maximum_.IsInt64())
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
else if (!CheckDoubleMaximum(context, static_cast<double>(i))) else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false; return false;
} }
@ -1217,11 +1234,11 @@ private:
PatternProperty* patternProperties_; PatternProperty* patternProperties_;
SizeType patternPropertyCount_; SizeType patternPropertyCount_;
SizeType propertyCount_; SizeType propertyCount_;
SizeType requiredCount_;
SizeType minProperties_; SizeType minProperties_;
SizeType maxProperties_; SizeType maxProperties_;
bool additionalProperties_; bool additionalProperties_;
bool hasDependencies_; bool hasDependencies_;
bool hasRequired_;
bool hasSchemaDependencies_; bool hasSchemaDependencies_;
const SchemaType* additionalItemsSchema_; const SchemaType* additionalItemsSchema_;
@ -1322,7 +1339,7 @@ public:
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
\param allocator An optional allocator instance for allocating memory. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null.
*/ */
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
remoteProvider_(remoteProvider), remoteProvider_(remoteProvider),
allocator_(allocator), allocator_(allocator),
ownAllocator_(), ownAllocator_(),
@ -1357,6 +1374,22 @@ public:
schemaRef_.ShrinkToFit(); // Deallocate all memory for ref schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
remoteProvider_(rhs.remoteProvider_),
allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
root_(rhs.root_),
schemaMap_(std::move(rhs.schemaMap_)),
schemaRef_(std::move(rhs.schemaRef_))
{
rhs.remoteProvider_ = 0;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
}
#endif
//! Destructor //! Destructor
~GenericSchemaDocument() { ~GenericSchemaDocument() {
while (!schemaMap_.Empty()) while (!schemaMap_.Empty())
@ -1369,6 +1402,11 @@ public:
const SchemaType& GetRoot() const { return *root_; } const SchemaType& GetRoot() const { return *root_; }
private: private:
//! Prohibit copying
GenericSchemaDocument(const GenericSchemaDocument&);
//! Prohibit assignment
GenericSchemaDocument& operator=(const GenericSchemaDocument&);
struct SchemaRefEntry { struct SchemaRefEntry {
SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
PointerType source; PointerType source;
@ -1397,8 +1435,6 @@ private:
const SchemaType* s = GetSchema(pointer); const SchemaType* s = GetSchema(pointer);
if (!s) if (!s)
CreateSchema(schema, pointer, v, document); CreateSchema(schema, pointer, v, document);
else if (schema)
*schema = s;
for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
@ -1438,7 +1474,7 @@ private:
if (i > 0) { // Remote reference, resolve immediately if (i > 0) { // Remote reference, resolve immediately
if (remoteProvider_) { if (remoteProvider_) {
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
PointerType pointer(&s[i], len - i, allocator_); PointerType pointer(&s[i], len - i, allocator_);
if (pointer.IsValid()) { if (pointer.IsValid()) {
if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
@ -1658,6 +1694,8 @@ RAPIDJSON_MULTILINEMACRO_END
bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
bool RawNumber(const Ch* str, SizeType length, bool copy)
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
bool String(const Ch* str, SizeType length, bool copy) bool String(const Ch* str, SizeType length, bool copy)
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
@ -1733,10 +1771,6 @@ RAPIDJSON_MULTILINEMACRO_END
return GetStateAllocator().Malloc(size); return GetStateAllocator().Malloc(size);
} }
virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) {
return GetStateAllocator().Realloc(originalPtr, originalSize, newSize);
}
virtual void FreeState(void* p) { virtual void FreeState(void* p) {
return StateAllocator::Free(p); return StateAllocator::Free(p);
} }
@ -1935,7 +1969,8 @@ public:
GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler); GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
parseResult_ = reader.template Parse<parseFlags>(is_, validator); parseResult_ = reader.template Parse<parseFlags>(is_, validator);
if ((isValid_ = validator.IsValid())) { isValid_ = validator.IsValid();
if (isValid_) {
invalidSchemaPointer_ = PointerType(); invalidSchemaPointer_ = PointerType();
invalidSchemaKeyword_ = 0; invalidSchemaKeyword_ = 0;
invalidDocumentPointer_ = PointerType(); invalidDocumentPointer_ = PointerType();
@ -1967,13 +2002,6 @@ private:
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__)
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_SCHEMA_H_ #endif // RAPIDJSON_SCHEMA_H_

View file

@ -95,7 +95,7 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
//! Put N copies of a character to a stream. //! Put N copies of a character to a stream.
template<typename Stream, typename Ch> template<typename Stream, typename Ch>
inline void PutN(Stream& stream, Ch c, size_t n) { inline void PutN(Stream& stream, Ch c, size_t n) {
PutReserve<Stream>(stream, n); PutReserve(stream, n);
for (size_t i = 0; i < n; i++) for (size_t i = 0; i < n; i++)
PutUnsafe(stream, c); PutUnsafe(stream, c);
} }

View file

@ -67,6 +67,7 @@ public:
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); } void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); } Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); } void Pop(size_t count) { stack_.template Pop<Ch>(count); }
const Ch* GetString() const { const Ch* GetString() const {
@ -77,8 +78,12 @@ public:
return stack_.template Bottom<Ch>(); return stack_.template Bottom<Ch>();
} }
//! Get the size of string in bytes in the string buffer.
size_t GetSize() const { return stack_.GetSize(); } size_t GetSize() const { return stack_.GetSize(); }
//! Get the length of string in Ch in the string buffer.
size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
static const size_t kDefaultCapacity = 256; static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_; mutable internal::Stack<Allocator> stack_;

View file

@ -23,6 +23,16 @@
#include "stringbuffer.h" #include "stringbuffer.h"
#include <new> // placement new #include <new> // placement new
#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 #ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
@ -31,10 +41,33 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// WriteFlag
/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
\ingroup RAPIDJSON_CONFIG
\brief User-defined kWriteDefaultFlags definition.
User can define this as any \c WriteFlag combinations.
*/
#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
#endif
//! Combination of writeFlags
enum WriteFlag {
kWriteNoFlags = 0, //!< No flags are set.
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
};
//! JSON writer //! JSON writer
/*! Writer implements the concept Handler. /*! Writer implements the concept Handler.
It generates JSON text by events to an output os. It generates JSON text by events to an output os.
@ -51,11 +84,13 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam StackAllocator Type of allocator for allocating memory of stack. \tparam StackAllocator Type of allocator for allocating memory of stack.
\note implements Handler concept \note implements Handler concept
*/ */
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class Writer { class Writer {
public: public:
typedef typename SourceEncoding::Ch Ch; typedef typename SourceEncoding::Ch Ch;
static const int kDefaultMaxDecimalPlaces = 324;
//! Constructor //! Constructor
/*! \param os Output stream. /*! \param os Output stream.
\param stackAllocator User supplied allocator. If it is null, it will create a private one. \param stackAllocator User supplied allocator. If it is null, it will create a private one.
@ -63,11 +98,18 @@ public:
*/ */
explicit explicit
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {} os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
explicit explicit
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Writer(Writer&& rhs) :
os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
rhs.os_ = 0;
}
#endif
//! Reset the writer with a new stream. //! Reset the writer with a new stream.
/*! /*!
@ -101,29 +143,66 @@ public:
return hasRoot_ && level_stack_.Empty(); return hasRoot_ && level_stack_.Empty();
} }
int GetMaxDecimalPlaces() const {
return maxDecimalPlaces_;
}
//! Sets the maximum number of decimal places for double output.
/*!
This setting truncates the output with specified number of decimal places.
For example,
\code
writer.SetMaxDecimalPlaces(3);
writer.StartArray();
writer.Double(0.12345); // "0.123"
writer.Double(0.0001); // "0.0"
writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
writer.EndArray();
\endcode
The default setting does not truncate any decimal places. You can restore to this setting by calling
\code
writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
\endcode
*/
void SetMaxDecimalPlaces(int maxDecimalPlaces) {
maxDecimalPlaces_ = maxDecimalPlaces;
}
/*!@name Implementation of Handler /*!@name Implementation of Handler
\see Handler \see Handler
*/ */
//@{ //@{
bool Null() { Prefix(kNullType); return WriteNull(); } bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
//! Writes the given \c double value to the stream //! Writes the given \c double value to the stream
/*! /*!
\param d The value to be written. \param d The value to be written.
\return Whether it is succeed. \return Whether it is succeed.
*/ */
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0);
(void)copy;
Prefix(kNumberType);
return EndValue(WriteString(str, length));
}
bool String(const Ch* str, SizeType length, bool copy = false) { bool String(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0);
(void)copy; (void)copy;
Prefix(kStringType); Prefix(kStringType);
return WriteString(str, length); return EndValue(WriteString(str, length));
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
@ -145,10 +224,7 @@ public:
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1); level_stack_.template Pop<Level>(1);
bool ret = WriteEndObject(); return EndValue(WriteEndObject());
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
os_->Flush();
return ret;
} }
bool StartArray() { bool StartArray() {
@ -162,10 +238,7 @@ public:
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray); RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1); level_stack_.template Pop<Level>(1);
bool ret = WriteEndArray(); return EndValue(WriteEndArray());
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
os_->Flush();
return ret;
} }
//@} //@}
@ -178,6 +251,20 @@ public:
//@} //@}
//! Write a raw JSON value.
/*!
For user to write a stringified JSON as a value.
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
\param length Length of the json.
\param type Type of the root of json.
*/
bool RawValue(const Ch* json, size_t length, Type type) {
RAPIDJSON_ASSERT(json != 0);
Prefix(type);
return EndValue(WriteRawValue(json, length));
}
protected: protected:
//! Information for each nested level //! Information for each nested level
struct Level { struct Level {
@ -242,8 +329,27 @@ protected:
} }
bool WriteDouble(double d) { bool WriteDouble(double d) {
if (internal::Double(d).IsNanOrInf()) {
if (!(writeFlags & kWriteNanAndInfFlag))
return false;
if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
return true;
}
if (internal::Double(d).Sign()) {
PutReserve(*os_, 9);
PutUnsafe(*os_, '-');
}
else
PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
return true;
}
char buffer[25]; char buffer[25];
char* end = internal::dtoa(d, buffer); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
PutReserve(*os_, static_cast<size_t>(end - buffer)); PutReserve(*os_, static_cast<size_t>(end - buffer));
for (char* p = buffer; p != end; ++p) for (char* p = buffer; p != end; ++p)
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
@ -271,7 +377,7 @@ protected:
PutUnsafe(*os_, '\"'); PutUnsafe(*os_, '\"');
GenericStringStream<SourceEncoding> is(str); GenericStringStream<SourceEncoding> is(str);
while (RAPIDJSON_LIKELY(is.Tell() < length)) { while (ScanWriteUnescapedString(is, length)) {
const Ch c = is.Peek(); const Ch c = is.Peek();
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) { if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
// Unicode escaping // Unicode escaping
@ -315,19 +421,33 @@ protected:
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]); PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
} }
} }
else else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
if (RAPIDJSON_UNLIKELY(!(Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_)))) Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
return false; Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
return false;
} }
PutUnsafe(*os_, '\"'); PutUnsafe(*os_, '\"');
return true; return true;
} }
bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
return RAPIDJSON_LIKELY(is.Tell() < length);
}
bool WriteStartObject() { os_->Put('{'); return true; } bool WriteStartObject() { os_->Put('{'); return true; }
bool WriteEndObject() { os_->Put('}'); return true; } bool WriteEndObject() { os_->Put('}'); return true; }
bool WriteStartArray() { os_->Put('['); return true; } bool WriteStartArray() { os_->Put('['); return true; }
bool WriteEndArray() { os_->Put(']'); return true; } bool WriteEndArray() { os_->Put(']'); return true; }
bool WriteRawValue(const Ch* json, size_t length) {
PutReserve(*os_, length);
for (size_t i = 0; i < length; i++) {
RAPIDJSON_ASSERT(json[i] != '\0');
PutUnsafe(*os_, json[i]);
}
return true;
}
void Prefix(Type type) { void Prefix(Type type) {
(void)type; (void)type;
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
@ -348,8 +468,16 @@ protected:
} }
} }
// Flush the value if it is the top level one.
bool EndValue(bool ret) {
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
os_->Flush();
return ret;
}
OutputStream* os_; OutputStream* os_;
internal::Stack<StackAllocator> level_stack_; internal::Stack<StackAllocator> level_stack_;
int maxDecimalPlaces_;
bool hasRoot_; bool hasRoot_;
private: private:
@ -394,12 +522,95 @@ inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
template<> template<>
inline bool Writer<StringBuffer>::WriteDouble(double d) { inline bool Writer<StringBuffer>::WriteDouble(double d) {
if (internal::Double(d).IsNanOrInf()) {
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
return false;
if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
return true;
}
if (internal::Double(d).Sign()) {
PutReserve(*os_, 9);
PutUnsafe(*os_, '-');
}
else
PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
return true;
}
char *buffer = os_->Push(25); char *buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
os_->Pop(static_cast<size_t>(25 - (end - buffer))); os_->Pop(static_cast<size_t>(25 - (end - buffer)));
return true; return true;
} }
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
template<>
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
if (length < 16)
return RAPIDJSON_LIKELY(is.Tell() < length);
if (!RAPIDJSON_LIKELY(is.Tell() < length))
return false;
const char* p = is.src_;
const char* end = is.head_ + length;
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
if (nextAligned > end)
return true;
while (p != nextAligned)
if (*p < 0x20 || *p == '\"' || *p == '\\') {
is.src_ = p;
return RAPIDJSON_LIKELY(is.Tell() < length);
}
else
os_->PutUnsafe(*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 != endAligned; 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 len;
#ifdef _MSC_VER // Find the index of first escaped
unsigned long offset;
_BitScanForward(&offset, r);
len = offset;
#else
len = static_cast<SizeType>(__builtin_ffs(r) - 1);
#endif
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
for (size_t i = 0; i < len; i++)
q[i] = p[i];
p += len;
break;
}
_mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
}
is.src_ = p;
return RAPIDJSON_LIKELY(is.Tell() < length);
}
#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#ifdef _MSC_VER #ifdef _MSC_VER