writer.h (rapidjson-1.0.2) | : | writer.h (rapidjson-1.1.0) | ||
---|---|---|---|---|
skipping to change at line 18 | skipping to change at line 18 | |||
// http://opensource.org/licenses/MIT | // http://opensource.org/licenses/MIT | |||
// | // | |||
// Unless required by applicable law or agreed to in writing, software distribut ed | // Unless required by applicable law or agreed to in writing, software distribut ed | |||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | |||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the | // CONDITIONS OF ANY KIND, either express or implied. See the License for the | |||
// specific language governing permissions and limitations under the License. | // specific language governing permissions and limitations under the License. | |||
#ifndef RAPIDJSON_WRITER_H_ | #ifndef RAPIDJSON_WRITER_H_ | |||
#define RAPIDJSON_WRITER_H_ | #define RAPIDJSON_WRITER_H_ | |||
#include "rapidjson.h" | #include "stream.h" | |||
#include "internal/stack.h" | #include "internal/stack.h" | |||
#include "internal/strfunc.h" | #include "internal/strfunc.h" | |||
#include "internal/dtoa.h" | #include "internal/dtoa.h" | |||
#include "internal/itoa.h" | #include "internal/itoa.h" | |||
#include "stringbuffer.h" | #include "stringbuffer.h" | |||
#include <new> // placement new | #include <new> // placement new | |||
#if RAPIDJSON_HAS_STDSTRING | #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) | |||
#include <string> | #include <intrin.h> | |||
#pragma intrinsic(_BitScanForward) | ||||
#endif | ||||
#ifdef RAPIDJSON_SSE42 | ||||
#include <nmmintrin.h> | ||||
#elif defined(RAPIDJSON_SSE2) | ||||
#include <emmintrin.h> | ||||
#endif | #endif | |||
#ifdef _MSC_VER | #ifdef _MSC_VER | |||
RAPIDJSON_DIAG_PUSH | RAPIDJSON_DIAG_PUSH | |||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | |||
#endif | #endif | |||
#ifdef __clang__ | ||||
RAPIDJSON_DIAG_PUSH | ||||
RAPIDJSON_DIAG_OFF(padded) | ||||
RAPIDJSON_DIAG_OFF(unreachable-code) | ||||
#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 an | ||||
d 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. | |||
User may programmatically calls the functions of a writer to generate JSON t ext. | User may programmatically calls the functions of a writer to generate JSON t ext. | |||
On the other side, a writer can also be passed to objects that generates eve nts, | On the other side, a writer can also be passed to objects that generates eve nts, | |||
for example Reader::Parse() and Document::Accept(). | for example Reader::Parse() and Document::Accept(). | |||
\tparam OutputStream Type of output stream. | \tparam OutputStream Type of output stream. | |||
\tparam SourceEncoding Encoding of source string. | \tparam SourceEncoding Encoding of source string. | |||
\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. | |||
\note implements Handler concept | \note implements Handler concept | |||
*/ | */ | |||
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename Targe tEncoding = UTF8<>, typename StackAllocator = CrtAllocator> | template<typename OutputStream, typename SourceEncoding = UTF8<>, typename Targe tEncoding = 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 cr eate a private one. | \param stackAllocator User supplied allocator. If it is null, it will cr eate a private one. | |||
\param levelDepth Initial capacity of stack. | \param levelDepth Initial capacity of stack. | |||
*/ | */ | |||
explicit | explicit | |||
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDep th = kDefaultLevelDepth) : | Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDep th = kDefaultLevelDepth) : | |||
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasR oot_(false) {} | os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxD ecimalPlaces_(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_(fa lse) {} | os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalP laces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} | |||
//! Reset the writer with a new stream. | //! Reset the writer with a new stream. | |||
/*! | /*! | |||
This function reset the writer with a new stream and default settings, | This function reset the writer with a new stream and default settings, | |||
in order to make a Writer object reusable for output multiple JSONs. | in order to make a Writer object reusable for output multiple JSONs. | |||
\param os New output stream. | \param os New output stream. | |||
\code | \code | |||
Writer<OutputStream> writer(os1); | Writer<OutputStream> writer(os1); | |||
writer.StartObject(); | writer.StartObject(); | |||
skipping to change at line 103 | skipping to change at line 138 | |||
} | } | |||
//! Checks whether the output is a complete JSON. | //! Checks whether the output is a complete JSON. | |||
/*! | /*! | |||
A complete JSON has a complete root object or array. | A complete JSON has a complete root object or array. | |||
*/ | */ | |||
bool IsComplete() const { | bool IsComplete() const { | |||
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 place | ||||
s. | ||||
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 no | ||||
t truncate significand for positive exponent) | ||||
writer.Double(1.23e-4); // "0.0" (do tr | ||||
uncate significand for negative exponent) | ||||
writer.EndArray(); | ||||
\endcode | ||||
The default setting does not truncate any decimal places. You can restor | ||||
e 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 Wri | ()); } | |||
teBool(b); } | bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return End | |||
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } | Value(WriteBool(b)); } | |||
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } | bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt( | |||
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } | i)); } | |||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); | bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint | |||
} | (u)); } | |||
bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt6 | ||||
4(i64)); } | ||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint | ||||
64(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(WriteDoub | |||
le(d)); } | ||||
bool RawNumber(const Ch* str, SizeType length, bool copy = false) { | ||||
(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) { | |||
(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 | |||
bool String(const std::basic_string<Ch>& str) { | bool String(const std::basic_string<Ch>& str) { | |||
return String(str.data(), SizeType(str.size())); | return String(str.data(), SizeType(str.size())); | |||
} | } | |||
#endif | #endif | |||
bool StartObject() { | bool StartObject() { | |||
Prefix(kObjectType); | Prefix(kObjectType); | |||
skipping to change at line 147 | skipping to change at line 217 | |||
return WriteStartObject(); | return WriteStartObject(); | |||
} | } | |||
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); } | |||
bool EndObject(SizeType memberCount = 0) { | bool EndObject(SizeType memberCount = 0) { | |||
(void)memberCount; | (void)memberCount; | |||
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 (level_stack_.Empty()) // end of json text | ||||
os_->Flush(); | ||||
return ret; | ||||
} | } | |||
bool StartArray() { | bool StartArray() { | |||
Prefix(kArrayType); | Prefix(kArrayType); | |||
new (level_stack_.template Push<Level>()) Level(true); | new (level_stack_.template Push<Level>()) Level(true); | |||
return WriteStartArray(); | return WriteStartArray(); | |||
} | } | |||
bool EndArray(SizeType elementCount = 0) { | bool EndArray(SizeType elementCount = 0) { | |||
(void)elementCount; | (void)elementCount; | |||
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 (level_stack_.Empty()) // end of json text | ||||
os_->Flush(); | ||||
return ret; | ||||
} | } | |||
//@} | //@} | |||
/*! @name Convenience extensions */ | /*! @name Convenience extensions */ | |||
//@{ | //@{ | |||
//! Simpler but slower overload. | //! Simpler but slower overload. | |||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); } | bool String(const Ch* str) { return String(str, internal::StrLen(str)); } | |||
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 charact | ||||
er 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) { Prefix(type); retu | ||||
rn EndValue(WriteRawValue(json, length)); } | ||||
protected: | protected: | |||
//! Information for each nested level | //! Information for each nested level | |||
struct Level { | struct Level { | |||
Level(bool inArray_) : valueCount(0), inArray(inArray_) {} | Level(bool inArray_) : valueCount(0), inArray(inArray_) {} | |||
size_t valueCount; //!< number of values in this level | size_t valueCount; //!< number of values in this level | |||
bool inArray; //!< true if in array, otherwise in object | bool inArray; //!< true if in array, otherwise in object | |||
}; | }; | |||
static const size_t kDefaultLevelDepth = 32; | static const size_t kDefaultLevelDepth = 32; | |||
bool WriteNull() { | bool WriteNull() { | |||
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; | PutReserve(*os_, 4); | |||
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUns | ||||
afe(*os_, 'l'); return true; | ||||
} | } | |||
bool WriteBool(bool b) { | bool WriteBool(bool b) { | |||
if (b) { | if (b) { | |||
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); | PutReserve(*os_, 4); | |||
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); Pu | ||||
tUnsafe(*os_, 'e'); | ||||
} | } | |||
else { | else { | |||
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put | PutReserve(*os_, 5); | |||
('e'); | PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); Pu | |||
tUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); | ||||
} | } | |||
return true; | return true; | |||
} | } | |||
bool WriteInt(int i) { | bool WriteInt(int i) { | |||
char buffer[11]; | char buffer[11]; | |||
const char* end = internal::i32toa(i, buffer); | const char* end = internal::i32toa(i, buffer); | |||
PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||
for (const char* p = buffer; p != end; ++p) | for (const char* p = buffer; p != end; ++p) | |||
os_->Put(*p); | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | |||
return true; | return true; | |||
} | } | |||
bool WriteUint(unsigned u) { | bool WriteUint(unsigned u) { | |||
char buffer[10]; | char buffer[10]; | |||
const char* end = internal::u32toa(u, buffer); | const char* end = internal::u32toa(u, buffer); | |||
PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||
for (const char* p = buffer; p != end; ++p) | for (const char* p = buffer; p != end; ++p) | |||
os_->Put(*p); | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | |||
return true; | return true; | |||
} | } | |||
bool WriteInt64(int64_t i64) { | bool WriteInt64(int64_t i64) { | |||
char buffer[21]; | char buffer[21]; | |||
const char* end = internal::i64toa(i64, buffer); | const char* end = internal::i64toa(i64, buffer); | |||
PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||
for (const char* p = buffer; p != end; ++p) | for (const char* p = buffer; p != end; ++p) | |||
os_->Put(*p); | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | |||
return true; | return true; | |||
} | } | |||
bool WriteUint64(uint64_t u64) { | bool WriteUint64(uint64_t u64) { | |||
char buffer[20]; | char buffer[20]; | |||
char* end = internal::u64toa(u64, buffer); | char* end = internal::u64toa(u64, buffer); | |||
PutReserve(*os_, static_cast<size_t>(end - buffer)); | ||||
for (char* p = buffer; p != end; ++p) | for (char* p = buffer; p != end; ++p) | |||
os_->Put(*p); | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | |||
return true; | return true; | |||
} | } | |||
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'); Pu | ||||
tUnsafe(*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)); | ||||
for (char* p = buffer; p != end; ++p) | for (char* p = buffer; p != end; ++p) | |||
os_->Put(*p); | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p)); | |||
return true; | return true; | |||
} | } | |||
bool WriteString(const Ch* str, SizeType length) { | bool WriteString(const Ch* str, SizeType length) { | |||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', ' 7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2' , '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; | |||
static const char escape[256] = { | static const char escape[256] = { | |||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 | |||
//0 1 2 3 4 5 6 7 8 9 A B C D E F | //0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r' , 'u', 'u', // 00 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r' , 'u', 'u', // 00 | |||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u' , 'u', 'u', // 10 | 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u' , 'u', 'u', // 10 | |||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, // 20 | 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, // 20 | |||
Z16, Z16, // 30~4F | Z16, Z16, // 30~4F | |||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0 , 0, 0, // 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0 , 0, 0, // 50 | |||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF | Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF | |||
#undef Z16 | #undef Z16 | |||
}; | }; | |||
os_->Put('\"'); | if (TargetEncoding::supportUnicode) | |||
PutReserve(*os_, 2 + length * 6); // "\uxxxx..." | ||||
else | ||||
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." | ||||
PutUnsafe(*os_, '\"'); | ||||
GenericStringStream<SourceEncoding> is(str); | GenericStringStream<SourceEncoding> is(str); | |||
while (is.Tell() < length) { | while (ScanWriteUnescapedString(is, length)) { | |||
const Ch c = is.Peek(); | const Ch c = is.Peek(); | |||
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { | if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0 x80) { | |||
// Unicode escaping | // Unicode escaping | |||
unsigned codepoint; | unsigned codepoint; | |||
if (!SourceEncoding::Decode(is, &codepoint)) | if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) | |||
return false; | return false; | |||
os_->Put('\\'); | PutUnsafe(*os_, '\\'); | |||
os_->Put('u'); | PutUnsafe(*os_, 'u'); | |||
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { | if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { | |||
os_->Put(hexDigits[(codepoint >> 12) & 15]); | PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); | |||
os_->Put(hexDigits[(codepoint >> 8) & 15]); | PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); | |||
os_->Put(hexDigits[(codepoint >> 4) & 15]); | PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); | |||
os_->Put(hexDigits[(codepoint ) & 15]); | PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); | |||
} | } | |||
else { | else { | |||
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10F FFF); | RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10F FFF); | |||
// Surrogate pair | // Surrogate pair | |||
unsigned s = codepoint - 0x010000; | unsigned s = codepoint - 0x010000; | |||
unsigned lead = (s >> 10) + 0xD800; | unsigned lead = (s >> 10) + 0xD800; | |||
unsigned trail = (s & 0x3FF) + 0xDC00; | unsigned trail = (s & 0x3FF) + 0xDC00; | |||
os_->Put(hexDigits[(lead >> 12) & 15]); | PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); | |||
os_->Put(hexDigits[(lead >> 8) & 15]); | PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); | |||
os_->Put(hexDigits[(lead >> 4) & 15]); | PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); | |||
os_->Put(hexDigits[(lead ) & 15]); | PutUnsafe(*os_, hexDigits[(lead ) & 15]); | |||
os_->Put('\\'); | PutUnsafe(*os_, '\\'); | |||
os_->Put('u'); | PutUnsafe(*os_, 'u'); | |||
os_->Put(hexDigits[(trail >> 12) & 15]); | PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); | |||
os_->Put(hexDigits[(trail >> 8) & 15]); | PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); | |||
os_->Put(hexDigits[(trail >> 4) & 15]); | PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); | |||
os_->Put(hexDigits[(trail ) & 15]); | PutUnsafe(*os_, hexDigits[(trail ) & 15]); | |||
} | } | |||
} | } | |||
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { | else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPI DJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) { | |||
is.Take(); | is.Take(); | |||
os_->Put('\\'); | PutUnsafe(*os_, '\\'); | |||
os_->Put(escape[(unsigned char)c]); | PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[ | |||
if (escape[(unsigned char)c] == 'u') { | static_cast<unsigned char>(c)])); | |||
os_->Put('0'); | if (escape[static_cast<unsigned char>(c)] == 'u') { | |||
os_->Put('0'); | PutUnsafe(*os_, '0'); | |||
os_->Put(hexDigits[(unsigned char)c >> 4]); | PutUnsafe(*os_, '0'); | |||
os_->Put(hexDigits[(unsigned char)c & 0xF]); | PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4 | |||
]); | ||||
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0x | ||||
F]); | ||||
} | } | |||
} | } | |||
else | else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFla | |||
if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, * | g ? | |||
os_)) | Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : | |||
return false; | Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, | |||
*os_)))) | ||||
return false; | ||||
} | } | |||
os_->Put('\"'); | 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 (level_stack_.GetSize() != 0) { // this value is not at root | if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is no t at root | |||
Level* level = level_stack_.template Top<Level>(); | Level* level = level_stack_.template Top<Level>(); | |||
if (level->valueCount > 0) { | if (level->valueCount > 0) { | |||
if (level->inArray) | if (level->inArray) | |||
os_->Put(','); // add comma if it is not the first element i n array | os_->Put(','); // add comma if it is not the first element i n array | |||
else // in object | else // in object | |||
os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); | os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); | |||
} | } | |||
if (!level->inArray && level->valueCount % 2 == 0) | if (!level->inArray && level->valueCount % 2 == 0) | |||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, th en even number should be a name | RAPIDJSON_ASSERT(type == kStringType); // if it's in object, th en even number should be a name | |||
level->valueCount++; | level->valueCount++; | |||
} | } | |||
else { | else { | |||
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. | RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. | |||
hasRoot_ = true; | hasRoot_ = true; | |||
} | } | |||
} | } | |||
// 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: | |||
// Prohibit copy constructor & assignment operator. | // Prohibit copy constructor & assignment operator. | |||
Writer(const Writer&); | Writer(const Writer&); | |||
Writer& operator=(const Writer&); | Writer& operator=(const Writer&); | |||
}; | }; | |||
// Full specialization for StringStream to prevent memory copying | // Full specialization for StringStream to prevent memory copying | |||
template<> | 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(11 - (end - buffer)); | os_->Pop(static_cast<size_t>(11 - (end - buffer))); | |||
return true; | return true; | |||
} | } | |||
template<> | 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(10 - (end - buffer)); | os_->Pop(static_cast<size_t>(10 - (end - buffer))); | |||
return true; | return true; | |||
} | } | |||
template<> | 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(21 - (end - buffer)); | os_->Pop(static_cast<size_t>(21 - (end - buffer))); | |||
return true; | return true; | |||
} | } | |||
template<> | 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(20 - (end - buffer)); | os_->Pop(static_cast<size_t>(20 - (end - buffer))); | |||
return true; | return true; | |||
} | } | |||
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'); PutUns | ||||
afe(*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(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, siz | ||||
e_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<si | ||||
ze_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, 0 | ||||
x19, 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 | |||
RAPIDJSON_DIAG_POP | RAPIDJSON_DIAG_POP | |||
#endif | #endif | |||
#ifdef __clang__ | ||||
RAPIDJSON_DIAG_POP | ||||
#endif | ||||
#endif // RAPIDJSON_RAPIDJSON_H_ | #endif // RAPIDJSON_RAPIDJSON_H_ | |||
End of changes. 54 change blocks. | ||||
75 lines changed or deleted | 324 lines changed or added |