1 // Tencent is pleased to support the open source community by making RapidJSON available.
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
8 // http://opensource.org/licenses/MIT
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
15 #ifndef RAPIDJSON_WRITER_H_
16 #define RAPIDJSON_WRITER_H_
19 #include "internal/meta.h"
20 #include "internal/stack.h"
21 #include "internal/strfunc.h"
22 #include "internal/dtoa.h"
23 #include "internal/itoa.h"
24 #include "stringbuffer.h"
25 #include <new> // placement new
27 #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
29 #pragma intrinsic(_BitScanForward)
31 #ifdef RAPIDJSON_SSE42
32 #include <nmmintrin.h>
33 #elif defined(RAPIDJSON_SSE2)
34 #include <emmintrin.h>
35 #elif defined(RAPIDJSON_NEON)
41 RAPIDJSON_DIAG_OFF(padded)
42 RAPIDJSON_DIAG_OFF(unreachable-code)
43 RAPIDJSON_DIAG_OFF(c++98-compat)
44 #elif defined(_MSC_VER)
46 RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
49 RAPIDJSON_NAMESPACE_BEGIN
51 ///////////////////////////////////////////////////////////////////////////////
54 /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
55 \ingroup RAPIDJSON_CONFIG
56 \brief User-defined kWriteDefaultFlags definition.
58 User can define this as any \c WriteFlag combinations.
60 #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
61 #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
64 //! Combination of writeFlags
66 kWriteNoFlags = 0, //!< No flags are set.
67 kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
68 kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
69 kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
73 /*! Writer implements the concept Handler.
74 It generates JSON text by events to an output os.
76 User may programmatically calls the functions of a writer to generate JSON text.
78 On the other side, a writer can also be passed to objects that generates events,
80 for example Reader::Parse() and Document::Accept().
82 \tparam OutputStream Type of output stream.
83 \tparam SourceEncoding Encoding of source string.
84 \tparam TargetEncoding Encoding of output stream.
85 \tparam StackAllocator Type of allocator for allocating memory of stack.
86 \note implements Handler concept
88 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
91 typedef typename SourceEncoding::Ch Ch;
93 static const int kDefaultMaxDecimalPlaces = 324;
96 /*! \param os Output stream.
97 \param stackAllocator User supplied allocator. If it is null, it will create a private one.
98 \param levelDepth Initial capacity of stack.
101 Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
102 os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
105 Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
106 os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
108 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
109 Writer(Writer&& rhs) :
110 os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
115 //! Reset the writer with a new stream.
117 This function reset the writer with a new stream and default settings,
118 in order to make a Writer object reusable for output multiple JSONs.
120 \param os New output stream.
122 Writer<OutputStream> writer(os1);
123 writer.StartObject();
128 writer.StartObject();
133 void Reset(OutputStream& os) {
136 level_stack_.Clear();
139 //! Checks whether the output is a complete JSON.
141 A complete JSON has a complete root object or array.
143 bool IsComplete() const {
144 return hasRoot_ && level_stack_.Empty();
147 int GetMaxDecimalPlaces() const {
148 return maxDecimalPlaces_;
151 //! Sets the maximum number of decimal places for double output.
153 This setting truncates the output with specified number of decimal places.
158 writer.SetMaxDecimalPlaces(3);
160 writer.Double(0.12345); // "0.123"
161 writer.Double(0.0001); // "0.0"
162 writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
163 writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
167 The default setting does not truncate any decimal places. You can restore to this setting by calling
169 writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
172 void SetMaxDecimalPlaces(int maxDecimalPlaces) {
173 maxDecimalPlaces_ = maxDecimalPlaces;
176 /*!@name Implementation of Handler
181 bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
182 bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
183 bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
184 bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
185 bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
186 bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
188 //! Writes the given \c double value to the stream
190 \param d The value to be written.
191 \return Whether it is succeed.
193 bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
195 bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
196 RAPIDJSON_ASSERT(str != 0);
199 return EndValue(WriteString(str, length));
202 bool String(const Ch* str, SizeType length, bool copy = false) {
203 RAPIDJSON_ASSERT(str != 0);
206 return EndValue(WriteString(str, length));
209 #if RAPIDJSON_HAS_STDSTRING
210 bool String(const std::basic_string<Ch>& str) {
211 return String(str.data(), SizeType(str.size()));
217 new (level_stack_.template Push<Level>()) Level(false);
218 return WriteStartObject();
221 bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
223 #if RAPIDJSON_HAS_STDSTRING
224 bool Key(const std::basic_string<Ch>& str)
226 return Key(str.data(), SizeType(str.size()));
230 bool EndObject(SizeType memberCount = 0) {
232 RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
233 RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
234 RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
235 level_stack_.template Pop<Level>(1);
236 return EndValue(WriteEndObject());
241 new (level_stack_.template Push<Level>()) Level(true);
242 return WriteStartArray();
245 bool EndArray(SizeType elementCount = 0) {
247 RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
248 RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
249 level_stack_.template Pop<Level>(1);
250 return EndValue(WriteEndArray());
254 /*! @name Convenience extensions */
257 //! Simpler but slower overload.
258 bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
259 bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
263 //! Write a raw JSON value.
265 For user to write a stringified JSON as a value.
267 \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
268 \param length Length of the json.
269 \param type Type of the root of json.
271 bool RawValue(const Ch* json, size_t length, Type type) {
272 RAPIDJSON_ASSERT(json != 0);
274 return EndValue(WriteRawValue(json, length));
277 //! Flush the output stream.
279 Allows the user to flush the output stream immediately.
286 //! Information for each nested level
288 Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
289 size_t valueCount; //!< number of values in this level
290 bool inArray; //!< true if in array, otherwise in object
293 static const size_t kDefaultLevelDepth = 32;
297 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
300 bool WriteBool(bool b) {
303 PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
307 PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
312 bool WriteInt(int i) {
314 const char* end = internal::i32toa(i, buffer);
315 PutReserve(*os_, static_cast<size_t>(end - buffer));
316 for (const char* p = buffer; p != end; ++p)
317 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
321 bool WriteUint(unsigned u) {
323 const char* end = internal::u32toa(u, buffer);
324 PutReserve(*os_, static_cast<size_t>(end - buffer));
325 for (const char* p = buffer; p != end; ++p)
326 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
330 bool WriteInt64(int64_t i64) {
332 const char* end = internal::i64toa(i64, buffer);
333 PutReserve(*os_, static_cast<size_t>(end - buffer));
334 for (const char* p = buffer; p != end; ++p)
335 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
339 bool WriteUint64(uint64_t u64) {
341 char* end = internal::u64toa(u64, buffer);
342 PutReserve(*os_, static_cast<size_t>(end - buffer));
343 for (char* p = buffer; p != end; ++p)
344 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
348 bool WriteDouble(double d) {
349 if (internal::Double(d).IsNanOrInf()) {
350 if (!(writeFlags & kWriteNanAndInfFlag))
352 if (internal::Double(d).IsNan()) {
354 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
357 if (internal::Double(d).Sign()) {
359 PutUnsafe(*os_, '-');
363 PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
364 PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
369 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
370 PutReserve(*os_, static_cast<size_t>(end - buffer));
371 for (char* p = buffer; p != end; ++p)
372 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
376 bool WriteString(const Ch* str, SizeType length) {
377 static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
378 static const char escape[256] = {
379 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
380 //0 1 2 3 4 5 6 7 8 9 A B C D E F
381 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
382 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
383 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
386 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
390 if (TargetEncoding::supportUnicode)
391 PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
393 PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
395 PutUnsafe(*os_, '\"');
396 GenericStringStream<SourceEncoding> is(str);
397 while (ScanWriteUnescapedString(is, length)) {
398 const Ch c = is.Peek();
399 if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
402 if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
404 PutUnsafe(*os_, '\\');
405 PutUnsafe(*os_, 'u');
406 if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
407 PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
408 PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
409 PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
410 PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
413 RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
415 unsigned s = codepoint - 0x010000;
416 unsigned lead = (s >> 10) + 0xD800;
417 unsigned trail = (s & 0x3FF) + 0xDC00;
418 PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
419 PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
420 PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
421 PutUnsafe(*os_, hexDigits[(lead ) & 15]);
422 PutUnsafe(*os_, '\\');
423 PutUnsafe(*os_, 'u');
424 PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
425 PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
426 PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
427 PutUnsafe(*os_, hexDigits[(trail ) & 15]);
430 else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
432 PutUnsafe(*os_, '\\');
433 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
434 if (escape[static_cast<unsigned char>(c)] == 'u') {
435 PutUnsafe(*os_, '0');
436 PutUnsafe(*os_, '0');
437 PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
438 PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
441 else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
442 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
443 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
446 PutUnsafe(*os_, '\"');
450 bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
451 return RAPIDJSON_LIKELY(is.Tell() < length);
454 bool WriteStartObject() { os_->Put('{'); return true; }
455 bool WriteEndObject() { os_->Put('}'); return true; }
456 bool WriteStartArray() { os_->Put('['); return true; }
457 bool WriteEndArray() { os_->Put(']'); return true; }
459 bool WriteRawValue(const Ch* json, size_t length) {
460 PutReserve(*os_, length);
461 GenericStringStream<SourceEncoding> is(json);
462 while (RAPIDJSON_LIKELY(is.Tell() < length)) {
463 RAPIDJSON_ASSERT(is.Peek() != '\0');
464 if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
465 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
466 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
472 void Prefix(Type type) {
474 if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
475 Level* level = level_stack_.template Top<Level>();
476 if (level->valueCount > 0) {
478 os_->Put(','); // add comma if it is not the first element in array
480 os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
482 if (!level->inArray && level->valueCount % 2 == 0)
483 RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
487 RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
492 // Flush the value if it is the top level one.
493 bool EndValue(bool ret) {
494 if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
500 internal::Stack<StackAllocator> level_stack_;
501 int maxDecimalPlaces_;
505 // Prohibit copy constructor & assignment operator.
506 Writer(const Writer&);
507 Writer& operator=(const Writer&);
510 // Full specialization for StringStream to prevent memory copying
513 inline bool Writer<StringBuffer>::WriteInt(int i) {
514 char *buffer = os_->Push(11);
515 const char* end = internal::i32toa(i, buffer);
516 os_->Pop(static_cast<size_t>(11 - (end - buffer)));
521 inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
522 char *buffer = os_->Push(10);
523 const char* end = internal::u32toa(u, buffer);
524 os_->Pop(static_cast<size_t>(10 - (end - buffer)));
529 inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
530 char *buffer = os_->Push(21);
531 const char* end = internal::i64toa(i64, buffer);
532 os_->Pop(static_cast<size_t>(21 - (end - buffer)));
537 inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
538 char *buffer = os_->Push(20);
539 const char* end = internal::u64toa(u, buffer);
540 os_->Pop(static_cast<size_t>(20 - (end - buffer)));
545 inline bool Writer<StringBuffer>::WriteDouble(double d) {
546 if (internal::Double(d).IsNanOrInf()) {
547 // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
548 if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
550 if (internal::Double(d).IsNan()) {
552 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
555 if (internal::Double(d).Sign()) {
557 PutUnsafe(*os_, '-');
561 PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
562 PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
566 char *buffer = os_->Push(25);
567 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
568 os_->Pop(static_cast<size_t>(25 - (end - buffer)));
572 #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
574 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
576 return RAPIDJSON_LIKELY(is.Tell() < length);
578 if (!RAPIDJSON_LIKELY(is.Tell() < length))
581 const char* p = is.src_;
582 const char* end = is.head_ + length;
583 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
584 const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
585 if (nextAligned > end)
588 while (p != nextAligned)
589 if (*p < 0x20 || *p == '\"' || *p == '\\') {
591 return RAPIDJSON_LIKELY(is.Tell() < length);
594 os_->PutUnsafe(*p++);
596 // The rest of string using SIMD
597 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
598 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
599 static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
600 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
601 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
602 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
604 for (; p != endAligned; p += 16) {
605 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
606 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
607 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
608 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
609 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
610 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
611 if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
613 #ifdef _MSC_VER // Find the index of first escaped
614 unsigned long offset;
615 _BitScanForward(&offset, r);
618 len = static_cast<SizeType>(__builtin_ffs(r) - 1);
620 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
621 for (size_t i = 0; i < len; i++)
627 _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
631 return RAPIDJSON_LIKELY(is.Tell() < length);
633 #elif defined(RAPIDJSON_NEON)
635 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
637 return RAPIDJSON_LIKELY(is.Tell() < length);
639 if (!RAPIDJSON_LIKELY(is.Tell() < length))
642 const char* p = is.src_;
643 const char* end = is.head_ + length;
644 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
645 const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
646 if (nextAligned > end)
649 while (p != nextAligned)
650 if (*p < 0x20 || *p == '\"' || *p == '\\') {
652 return RAPIDJSON_LIKELY(is.Tell() < length);
655 os_->PutUnsafe(*p++);
657 // The rest of string using SIMD
658 const uint8x16_t s0 = vmovq_n_u8('"');
659 const uint8x16_t s1 = vmovq_n_u8('\\');
660 const uint8x16_t s2 = vmovq_n_u8('\b');
661 const uint8x16_t s3 = vmovq_n_u8(32);
663 for (; p != endAligned; p += 16) {
664 const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
665 uint8x16_t x = vceqq_u8(s, s0);
666 x = vorrq_u8(x, vceqq_u8(s, s1));
667 x = vorrq_u8(x, vceqq_u8(s, s2));
668 x = vorrq_u8(x, vcltq_u8(s, s3));
670 x = vrev64q_u8(x); // Rev in 64
671 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
672 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
675 bool escaped = false;
678 unsigned lz = (unsigned)__builtin_clzll(high);
683 unsigned lz = (unsigned)__builtin_clzll(low);
687 if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
688 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
689 for (size_t i = 0; i < len; i++)
695 vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
699 return RAPIDJSON_LIKELY(is.Tell() < length);
701 #endif // RAPIDJSON_NEON
703 RAPIDJSON_NAMESPACE_END
705 #if defined(_MSC_VER) || defined(__clang__)
709 #endif // RAPIDJSON_RAPIDJSON_H_