Merge pull request #977 from assimp/update_rapidjson_version_1_0_2

Update rapidjson to v1.0.2
pull/983/head
Kim Kulling 2016-08-14 12:24:39 +02:00 committed by GitHub
commit 6ae545b609
15 changed files with 79 additions and 291 deletions

View File

@ -181,7 +181,7 @@ public:
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
chunkHead_->size += size; chunkHead_->size += size;
return buffer; return buffer;
} }
@ -199,7 +199,7 @@ public:
return originalPtr; return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space // Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize); size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment); increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) { if (chunkHead_->size + increment <= chunkHead_->capacity) {
@ -231,7 +231,7 @@ private:
void AddChunk(size_t capacity) { void 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)); ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
chunk->capacity = capacity; chunk->capacity = capacity;
chunk->size = 0; chunk->size = 0;
chunk->next = chunkHead_; chunk->next = chunkHead_;

View File

@ -69,9 +69,6 @@ RAPIDJSON_NAMESPACE_BEGIN
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
class GenericValue; class GenericValue;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
//! Name-value pair in a JSON object value. //! Name-value pair in a JSON object value.
/*! /*!
This class was internal to GenericValue. It used to be a inner struct. This class was internal to GenericValue. It used to be a inner struct.
@ -449,16 +446,6 @@ private:
//! Copy constructor is not permitted. //! Copy constructor is not permitted.
GenericValue(const GenericValue& rhs); GenericValue(const GenericValue& rhs);
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Moving from a GenericDocument is not permitted.
template <typename StackAllocator>
GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
//! Move assignment from a GenericDocument is not permitted.
template <typename StackAllocator>
GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
#endif
public: public:
//! Constructor with JSON value type. //! Constructor with JSON value type.
@ -545,28 +532,6 @@ public:
flags_ |= kIntFlag; flags_ |= kIntFlag;
} }
#if defined(__APPLE__)
//! Constructor for unsigned long value.
explicit GenericValue(unsigned long u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
data_.n.u64 = u64;
if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
flags_ |= kInt64Flag;
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
flags_ |= kUintFlag;
if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
flags_ |= kIntFlag;
}
#if !defined(__x86_64__) && !defined(__arm64__)
//! Constructor for size_t value.
explicit GenericValue( size_t u ) RAPIDJSON_NOEXCEPT : data_(), flags_( kNumberUintFlag ) {
data_.n.u64 = u;
if ( !( u&0x80000000 ) )
flags_ |= kIntFlag|kInt64Flag;
}
#endif
#endif
//! Constructor for double value. //! Constructor for double value.
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
@ -695,20 +660,6 @@ public:
return *this; return *this;
} }
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
\code
void swap(MyClass& a, MyClass& b) {
using std::swap;
swap(a.value, b.value);
// ...
}
\endcode
\see Swap()
*/
friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//! Prepare Value for move semantics //! Prepare Value for move semantics
/*! \return *this */ /*! \return *this */
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
@ -1262,31 +1213,6 @@ public:
return pos; return pos;
} }
//! Erase a member in object by its name.
/*! \param name Name of member to be removed.
\return Whether the member existed.
\note Linear time complexity.
*/
bool EraseMember(const Ch* name) {
GenericValue n(StringRef(name));
return EraseMember(n);
}
#if RAPIDJSON_HAS_STDSTRING
bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator>
bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name);
if (m != MemberEnd()) {
EraseMember(m);
return true;
}
else
return false;
}
//@} //@}
//!@name Array //!@name Array
@ -1798,22 +1724,7 @@ public:
typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter.
//! Constructor //! Constructor
/*! Creates an empty document of specified type. /*! \param allocator Optional allocator for allocating memory.
\param type Mandatory type of object to create.
\param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack.
*/
explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
}
//! Constructor
/*! Creates an empty document which type is Null.
\param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes. \param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack. \param stackAllocator Optional allocator for allocating memory for stack.
*/ */
@ -1827,7 +1738,7 @@ public:
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11 //! Move constructor in C++11
GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
: ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document : ValueType(std::move(rhs)),
allocator_(rhs.allocator_), allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_), ownAllocator_(rhs.ownAllocator_),
stack_(std::move(rhs.stack_)), stack_(std::move(rhs.stack_)),
@ -1867,35 +1778,6 @@ public:
} }
#endif #endif
//! Exchange the contents of this document with those of another.
/*!
\param other Another document.
\note Constant complexity.
\see GenericValue::Swap
*/
GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
ValueType::Swap(rhs);
stack_.Swap(rhs.stack_);
internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(parseResult_, rhs.parseResult_);
return *this;
}
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
\code
void swap(MyClass& a, MyClass& b) {
using std::swap;
swap(a.doc, b.doc);
// ...
}
\endcode
\see Swap()
*/
friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//!@name Parse from stream //!@name Parse from stream
//!@{ //!@{
@ -1908,13 +1790,13 @@ public:
*/ */
template <unsigned parseFlags, typename SourceEncoding, typename InputStream> template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
GenericDocument& ParseStream(InputStream& is) { GenericDocument& ParseStream(InputStream& is) {
GenericReader<SourceEncoding, Encoding, StackAllocator> reader( ValueType::SetNull(); // Remove existing root if exist
stack_.HasAllocator() ? &stack_.GetAllocator() : 0); GenericReader<SourceEncoding, Encoding, StackAllocator> reader(&stack_.GetAllocator());
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
parseResult_ = reader.template Parse<parseFlags>(is, *this); parseResult_ = reader.template Parse<parseFlags>(is, *this);
if (parseResult_) { if (parseResult_) {
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
} }
return *this; return *this;
} }
@ -2011,10 +1893,7 @@ public:
//!@} //!@}
//! Get the allocator of this document. //! Get the allocator of this document.
Allocator& GetAllocator() { Allocator& GetAllocator() { return *allocator_; }
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
//! Get the capacity of stack in bytes. //! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); } size_t GetStackCapacity() const { return stack_.GetCapacity(); }
@ -2123,7 +2002,6 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
default: // kNumberType, kTrueType, kFalseType, kNullType default: // kNumberType, kTrueType, kFalseType, kNullType
flags_ = rhs.flags_; flags_ = rhs.flags_;
data_ = *reinterpret_cast<const Data*>(&rhs.data_); data_ = *reinterpret_cast<const Data*>(&rhs.data_);
break;
} }
} }

View File

@ -77,8 +77,8 @@ public:
void Flush() { os_.Flush(); } void Flush() { os_.Flush(); }
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Peek() const { RAPIDJSON_ASSERT(false); }
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
@ -146,7 +146,7 @@ private:
if (!c) if (!c)
return; return;
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
hasBOM_ = false; hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
@ -227,8 +227,8 @@ public:
void Flush() { os_->Flush(); } void Flush() { os_->Flush(); }
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Peek() const { RAPIDJSON_ASSERT(false); }
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }

View File

@ -57,11 +57,7 @@ public:
void Flush() { void Flush() {
if (current_ != buffer_) { if (current_ != buffer_) {
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) {
// failure deliberately ignored at this time
// added to avoid warn_unused_result build errors
}
current_ = buffer_; current_ = buffer_;
} }
} }

View File

@ -19,7 +19,6 @@
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128 #include <intrin.h> // for _umul128
#pragma intrinsic(_umul128)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -51,16 +50,7 @@ public:
if (length > 0) if (length > 0)
AppendDecimal64(decimals + i, decimals + i + length); AppendDecimal64(decimals + i, decimals + i + length);
} }
BigInteger& operator=(const BigInteger &rhs)
{
if (this != &rhs) {
count_ = rhs.count_;
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
return *this;
}
BigInteger& operator=(uint64_t u) { BigInteger& operator=(uint64_t u) {
digits_[0] = u; digits_[0] = u;
count_ = 1; count_ = 1;
@ -240,7 +230,7 @@ private:
uint64_t r = 0; uint64_t r = 0;
for (const char* p = begin; p != end; ++p) { for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + (unsigned)(*p - '0'); r = r * 10 + (*p - '0');
} }
return r; return r;
} }

View File

@ -24,7 +24,6 @@
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h> #include <intrin.h>
#pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_umul128)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -233,8 +232,8 @@ inline DiyFp GetCachedPower(int e, int* K) {
} }
inline DiyFp GetCachedPower10(int exp, int *outExp) { inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u; unsigned index = (exp + 348) / 8;
*outExp = -348 + static_cast<int>(index) * 8; *outExp = -348 + index * 8;
return GetCachedPowerByIndex(index); return GetCachedPowerByIndex(index);
} }

View File

@ -62,7 +62,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
const DiyFp wp_w = Mp - W; const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1); uint64_t p2 = Mp.f & (one.f - 1);
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0; *len = 0;
while (kappa > 0) { while (kappa > 0) {
@ -101,7 +101,7 @@ 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)]); GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
return; return;
} }
} }
@ -158,14 +158,14 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
else if (0 < kk && kk <= 21) { else if (0 < kk && kk <= 21) {
// 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], length - kk);
buffer[kk] = '.'; buffer[kk] = '.';
return &buffer[length + 1]; return &buffer[length + 1];
} }
else if (-6 < kk && kk <= 0) { else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234 // 1234e-6 -> 0.001234
const int offset = 2 - kk; const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); std::memmove(&buffer[offset], &buffer[0], length);
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
for (int i = 2; i < offset; i++) for (int i = 2; i < offset; i++)
@ -179,7 +179,7 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
else { else {
// 1234e30 -> 1.234e33 // 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); std::memmove(&buffer[2], &buffer[1], length - 1);
buffer[1] = '.'; buffer[1] = '.';
buffer[length + 1] = 'e'; buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]); return WriteExponent(kk - 1, &buffer[0 + length + 2]);

View File

@ -53,7 +53,7 @@ public:
else if (order <= -1074) else if (order <= -1074)
return 0; return 0;
else else
return (unsigned)order + 1074; return order + 1074;
} }
private: private:

View File

@ -16,7 +16,6 @@
#define RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_
#include "../rapidjson.h" #include "../rapidjson.h"
#include "swap.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
@ -82,15 +81,6 @@ public:
} }
#endif #endif
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_);
internal::Swap(stackEnd_, rhs.stackEnd_);
internal::Swap(initialCapacity_, rhs.initialCapacity_);
}
void Clear() { stackTop_ = stack_; } void Clear() { stackTop_ = stack_; }
void ShrinkToFit() { void ShrinkToFit() {
@ -134,14 +124,7 @@ public:
template<typename T> template<typename T>
T* Bottom() { return (T*)stack_; } T* Bottom() { return (T*)stack_; }
bool HasAllocator() const { Allocator& GetAllocator() { return *allocator_; }
return allocator_ != 0;
}
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
bool Empty() const { return stackTop_ == stack_; } bool Empty() const { return stackTop_ == stack_; }
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); } size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }

View File

@ -95,13 +95,13 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
hS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2;
BigInteger dS = d; BigInteger dS = d;
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2); dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;
BigInteger bS(bInt); BigInteger bS(bInt);
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2); bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;
BigInteger hS(1); BigInteger hS(1);
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2); hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
BigInteger delta(0); BigInteger delta(0);
dS.Difference(bS, &delta); dS.Difference(bS, &delta);
@ -134,7 +134,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break; break;
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0'); significand = significand * 10 + (decimals[i] - '0');
} }
if (i < length && decimals[i] >= '5') // Rounding if (i < length && decimals[i] >= '5') // Rounding
@ -163,10 +163,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
}; };
int adjustment = dExp - actualExp - 1; int adjustment = dExp - actualExp - 1;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment]; v = v * kPow10[adjustment];
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit if (length + adjustment > 19) // has more digits than decimal digits in 64-bit
error += kUlp / 2; error += kUlp / 2;
} }
@ -184,14 +184,14 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
unsigned scaleExp = (precisionSize + kUlpShift) - 63; unsigned scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp; v.f >>= scaleExp;
v.e += scaleExp; v.e += scaleExp;
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp); error = (error >> scaleExp) + 1 + kUlp;
precisionSize -= scaleExp; precisionSize -= scaleExp;
} }
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize)); DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) { if (precisionBits >= halfWay + error) {
rounded.f++; rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1; rounded.f >>= 1;
@ -201,7 +201,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
*result = rounded.ToDouble(); *result = rounded.ToDouble();
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error); return halfWay - error >= precisionBits || precisionBits >= halfWay + error;
} }
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
@ -249,7 +249,7 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t
if ((int)length > kMaxDecimalDigit) { if ((int)length > kMaxDecimalDigit) {
int delta = (int(length) - kMaxDecimalDigit); int delta = (int(length) - kMaxDecimalDigit);
exp += delta; exp += delta;
decimalPosition -= static_cast<unsigned>(delta); decimalPosition -= delta;
length = kMaxDecimalDigit; length = kMaxDecimalDigit;
} }

View File

@ -223,7 +223,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(_WIN64)
#define RAPIDJSON_64BIT 1 #define RAPIDJSON_64BIT 1
#else #else
#define RAPIDJSON_64BIT 0 #define RAPIDJSON_64BIT 0
@ -238,13 +238,13 @@
\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. User can customize by defining the RAPIDJSON_ALIGN function macro.,
*/ */
#ifndef RAPIDJSON_ALIGN #ifndef RAPIDJSON_ALIGN
#if RAPIDJSON_64BIT == 1 #if RAPIDJSON_64BIT == 1
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u)) #define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u)
#else #else
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) #define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
#endif #endif
#endif #endif

View File

@ -140,7 +140,6 @@ enum ParseFlag {
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, 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.
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
}; };
@ -272,7 +271,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
// The rest of string using SIMD // The rest of string using SIMD
static const char whitespace[16] = " \n\r\t"; static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]);
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128((const __m128i *)p); const __m128i s = _mm_load_si128((const __m128i *)p);
@ -399,8 +398,7 @@ public:
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (is.Peek() == '\0') { if (is.Peek() == '\0') {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
@ -411,8 +409,7 @@ public:
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (!(parseFlags & kParseStopWhenDoneFlag)) { if (!(parseFlags & kParseStopWhenDoneFlag)) {
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (is.Peek() != '\0') { if (is.Peek() != '\0') {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
@ -465,40 +462,6 @@ private:
ClearStackOnExit& operator=(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&);
}; };
template<unsigned parseFlags, typename InputStream>
void SkipWhitespaceAndComments(InputStream& is) {
SkipWhitespace(is);
if (parseFlags & kParseCommentsFlag) {
while (is.Peek() == '/') {
is.Take();
if (is.Peek() == '*') {
is.Take();
while (true) {
if (is.Peek() == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
if (is.Take() == '*') {
if (is.Peek() == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
if (is.Take() == '/')
break;
}
}
} else if (is.Peek() == '/') {
is.Take();
while (is.Peek() != '\0' && is.Take() != '\n') { }
} else {
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
}
SkipWhitespace(is);
}
}
}
// Parse object: { string : value, ... } // Parse object: { string : value, ... }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseObject(InputStream& is, Handler& handler) { void ParseObject(InputStream& is, Handler& handler) {
@ -508,8 +471,7 @@ private:
if (!handler.StartObject()) if (!handler.StartObject())
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == '}') { if (is.Peek() == '}') {
is.Take(); is.Take();
@ -525,35 +487,27 @@ private:
ParseString<parseFlags>(is, handler, true); ParseString<parseFlags>(is, handler, true);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Take() != ':') if (is.Take() != ':')
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
++memberCount; ++memberCount;
switch (is.Take()) { switch (is.Take()) {
case ',': case ',': SkipWhitespace(is); break;
SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break;
case '}': case '}':
if (!handler.EndObject(memberCount)) if (!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;
} }
} }
} }
@ -567,8 +521,7 @@ private:
if (!handler.StartArray()) if (!handler.StartArray())
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == ']') { if (is.Peek() == ']') {
is.Take(); is.Take();
@ -582,21 +535,15 @@ private:
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
++elementCount; ++elementCount;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
switch (is.Take()) { switch (is.Take()) {
case ',': case ',': SkipWhitespace(is); break;
SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break;
case ']': case ']':
if (!handler.EndArray(elementCount)) if (!handler.EndArray(elementCount))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
return; return;
default: default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
break;
} }
} }
} }
@ -1020,13 +967,13 @@ private:
else { else {
if (use64bit) { if (use64bit) {
if (minus) if (minus)
cont = handler.Int64(static_cast<int64_t>(~i64 + 1)); cont = handler.Int64(-(int64_t)i64);
else else
cont = handler.Uint64(i64); cont = handler.Uint64(i64);
} }
else { else {
if (minus) if (minus)
cont = handler.Int(static_cast<int32_t>(~i + 1)); cont = handler.Int(-(int)i);
else else
cont = handler.Uint(i); cont = handler.Uint(i);
} }
@ -1045,10 +992,7 @@ private:
case '"': ParseString<parseFlags>(is, handler); break; case '"': ParseString<parseFlags>(is, handler); break;
case '{': ParseObject<parseFlags>(is, handler); break; case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray <parseFlags>(is, handler); break; case '[': ParseArray <parseFlags>(is, handler); break;
default : default : ParseNumber<parseFlags>(is, handler);
ParseNumber<parseFlags>(is, handler);
break;
} }
} }
@ -1443,14 +1387,14 @@ private:
} }
switch (src) { switch (src) {
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
case IterativeParsingObjectInitialState: case IterativeParsingObjectInitialState:
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
} }
} }
@ -1460,8 +1404,7 @@ private:
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
IterativeParsingState state = IterativeParsingStartState; IterativeParsingState state = IterativeParsingStartState;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
while (is.Peek() != '\0') { while (is.Peek() != '\0') {
Token t = Tokenize(is.Peek()); Token t = Tokenize(is.Peek());
IterativeParsingState n = Predict(state, t); IterativeParsingState n = Predict(state, t);
@ -1478,8 +1421,7 @@ private:
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
break; break;
SkipWhitespaceAndComments<parseFlags>(is); SkipWhitespace(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
// Handle the end of file. // Handle the end of file.

View File

@ -350,7 +350,7 @@ template<>
inline bool Writer<StringBuffer>::WriteInt(int i) { inline bool Writer<StringBuffer>::WriteInt(int i) {
char *buffer = os_->Push(11); char *buffer = os_->Push(11);
const char* end = internal::i32toa(i, buffer); const char* end = internal::i32toa(i, buffer);
os_->Pop(static_cast<size_t>(11 - (end - buffer))); os_->Pop(11 - (end - buffer));
return true; return true;
} }
@ -358,7 +358,7 @@ template<>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) { inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
char *buffer = os_->Push(10); char *buffer = os_->Push(10);
const char* end = internal::u32toa(u, buffer); const char* end = internal::u32toa(u, buffer);
os_->Pop(static_cast<size_t>(10 - (end - buffer))); os_->Pop(10 - (end - buffer));
return true; return true;
} }
@ -366,7 +366,7 @@ template<>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
char *buffer = os_->Push(21); char *buffer = os_->Push(21);
const char* end = internal::i64toa(i64, buffer); const char* end = internal::i64toa(i64, buffer);
os_->Pop(static_cast<size_t>(21 - (end - buffer))); os_->Pop(21 - (end - buffer));
return true; return true;
} }
@ -374,7 +374,7 @@ template<>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
char *buffer = os_->Push(20); char *buffer = os_->Push(20);
const char* end = internal::u64toa(u, buffer); const char* end = internal::u64toa(u, buffer);
os_->Pop(static_cast<size_t>(20 - (end - buffer))); os_->Pop(20 - (end - buffer));
return true; return true;
} }
@ -382,7 +382,7 @@ template<>
inline bool Writer<StringBuffer>::WriteDouble(double d) { inline bool Writer<StringBuffer>::WriteDouble(double d) {
char *buffer = os_->Push(25); char *buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer); char* end = internal::dtoa(d, buffer);
os_->Pop(static_cast<size_t>(25 - (end - buffer))); os_->Pop(25 - (end - buffer));
return true; return true;
} }

View File

@ -3,7 +3,7 @@ Tencent is pleased to support the open source community by making RapidJSON avai
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON.
A copy of the MIT License is included in this file. A copy of the MIT License is included in this file.
Other dependencies and licenses: Other dependencies and licenses:

View File

@ -10,8 +10,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) * [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
* RapidJSON Documentation * RapidJSON Documentation
* [English](http://rapidjson.org/) * [English](http://miloyip.github.io/rapidjson/)
* [简体中文](http://rapidjson.org/zh-cn/) * [简体中文](http://miloyip.github.io/rapidjson/zh-cn/)
* [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference.
## Build status ## Build status
@ -31,15 +31,15 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/). RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/).
* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. * RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. * RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration.
* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL. * RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL.
* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. * RapidJSON is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). * RapidJSON is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
More features can be read [here](doc/features.md). More features can be read [here](doc/features.md).