1// Tencent is pleased to support the open source community by making RapidJSON available.
2//
3// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4//
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
7//
8// http://opensource.org/licenses/MIT
9//
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.
14
15#ifndef RAPIDJSON_WRITER_H_
16#define RAPIDJSON_WRITER_H_
17
18#include "stream.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
26
27#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
28#include <intrin.h>
29#pragma intrinsic(_BitScanForward)
30#endif
31#ifdef RAPIDJSON_SSE42
32#include <nmmintrin.h>
33#elif defined(RAPIDJSON_SSE2)
34#include <emmintrin.h>
35#elif defined(RAPIDJSON_NEON)
36#include <arm_neon.h>
37#endif
38
39#ifdef __clang__
40RAPIDJSON_DIAG_PUSH
41RAPIDJSON_DIAG_OFF(padded)
42RAPIDJSON_DIAG_OFF(unreachable-code)
43RAPIDJSON_DIAG_OFF(c++98-compat)
44#elif defined(_MSC_VER)
45RAPIDJSON_DIAG_PUSH
46RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
47#endif
48
49RAPIDJSON_NAMESPACE_BEGIN
50
51///////////////////////////////////////////////////////////////////////////////
52// WriteFlag
53
54/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
55 \ingroup RAPIDJSON_CONFIG
56 \brief User-defined kWriteDefaultFlags definition.
57
58 User can define this as any \c WriteFlag combinations.
59*/
60#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
61#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
62#endif
63
64//! Combination of writeFlags
65enum WriteFlag {
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
70};
71
72//! JSON writer
73/*! Writer implements the concept Handler.
74 It generates JSON text by events to an output os.
75
76 User may programmatically calls the functions of a writer to generate JSON text.
77
78 On the other side, a writer can also be passed to objects that generates events,
79
80 for example Reader::Parse() and Document::Accept().
81
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
87*/
88template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
89class Writer {
90public:
91 typedef typename SourceEncoding::Ch Ch;
92
93 static const int kDefaultMaxDecimalPlaces = 324;
94
95 //! Constructor
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.
99 */
100 explicit
101 Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
102 os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
103
104 explicit
105 Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
106 os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
107
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_) {
111 rhs.os_ = 0;
112 }
113#endif
114
115 //! Reset the writer with a new stream.
116 /*!
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.
119
120 \param os New output stream.
121 \code
122 Writer<OutputStream> writer(os1);
123 writer.StartObject();
124 // ...
125 writer.EndObject();
126
127 writer.Reset(os2);
128 writer.StartObject();
129 // ...
130 writer.EndObject();
131 \endcode
132 */
133 void Reset(OutputStream& os) {
134 os_ = &os;
135 hasRoot_ = false;
136 level_stack_.Clear();
137 }
138
139 //! Checks whether the output is a complete JSON.
140 /*!
141 A complete JSON has a complete root object or array.
142 */
143 bool IsComplete() const {
144 return hasRoot_ && level_stack_.Empty();
145 }
146
147 int GetMaxDecimalPlaces() const {
148 return maxDecimalPlaces_;
149 }
150
151 //! Sets the maximum number of decimal places for double output.
152 /*!
153 This setting truncates the output with specified number of decimal places.
154
155 For example,
156
157 \code
158 writer.SetMaxDecimalPlaces(3);
159 writer.StartArray();
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)
164 writer.EndArray();
165 \endcode
166
167 The default setting does not truncate any decimal places. You can restore to this setting by calling
168 \code
169 writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
170 \endcode
171 */
172 void SetMaxDecimalPlaces(int maxDecimalPlaces) {
173 maxDecimalPlaces_ = maxDecimalPlaces;
174 }
175
176 /*!@name Implementation of Handler
177 \see Handler
178 */
179 //@{
180
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)); }
187
188 //! Writes the given \c double value to the stream
189 /*!
190 \param d The value to be written.
191 \return Whether it is succeed.
192 */
193 bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
194
195 bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
196 RAPIDJSON_ASSERT(str != 0);
197 (void)copy;
198 Prefix(kNumberType);
199 return EndValue(WriteString(str, length));
200 }
201
202 bool String(const Ch* str, SizeType length, bool copy = false) {
203 RAPIDJSON_ASSERT(str != 0);
204 (void)copy;
205 Prefix(kStringType);
206 return EndValue(WriteString(str, length));
207 }
208
209#if RAPIDJSON_HAS_STDSTRING
210 bool String(const std::basic_string<Ch>& str) {
211 return String(str.data(), SizeType(str.size()));
212 }
213#endif
214
215 bool StartObject() {
216 Prefix(kObjectType);
217 new (level_stack_.template Push<Level>()) Level(false);
218 return WriteStartObject();
219 }
220
221 bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
222
223#if RAPIDJSON_HAS_STDSTRING
224 bool Key(const std::basic_string<Ch>& str)
225 {
226 return Key(str.data(), SizeType(str.size()));
227 }
228#endif
229
230 bool EndObject(SizeType memberCount = 0) {
231 (void)memberCount;
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());
237 }
238
239 bool StartArray() {
240 Prefix(kArrayType);
241 new (level_stack_.template Push<Level>()) Level(true);
242 return WriteStartArray();
243 }
244
245 bool EndArray(SizeType elementCount = 0) {
246 (void)elementCount;
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());
251 }
252 //@}
253
254 /*! @name Convenience extensions */
255 //@{
256
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)); }
260
261 //@}
262
263 //! Write a raw JSON value.
264 /*!
265 For user to write a stringified JSON as a value.
266
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.
270 */
271 bool RawValue(const Ch* json, size_t length, Type type) {
272 RAPIDJSON_ASSERT(json != 0);
273 Prefix(type);
274 return EndValue(WriteRawValue(json, length));
275 }
276
277 //! Flush the output stream.
278 /*!
279 Allows the user to flush the output stream immediately.
280 */
281 void Flush() {
282 os_->Flush();
283 }
284
285protected:
286 //! Information for each nested level
287 struct 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
291 };
292
293 static const size_t kDefaultLevelDepth = 32;
294
295 bool WriteNull() {
296 PutReserve(*os_, 4);
297 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
298 }
299
300 bool WriteBool(bool b) {
301 if (b) {
302 PutReserve(*os_, 4);
303 PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
304 }
305 else {
306 PutReserve(*os_, 5);
307 PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
308 }
309 return true;
310 }
311
312 bool WriteInt(int i) {
313 char buffer[11];
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));
318 return true;
319 }
320
321 bool WriteUint(unsigned u) {
322 char buffer[10];
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));
327 return true;
328 }
329
330 bool WriteInt64(int64_t i64) {
331 char buffer[21];
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));
336 return true;
337 }
338
339 bool WriteUint64(uint64_t u64) {
340 char buffer[20];
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));
345 return true;
346 }
347
348 bool WriteDouble(double d) {
349 if (internal::Double(d).IsNanOrInf()) {
350 if (!(writeFlags & kWriteNanAndInfFlag))
351 return false;
352 if (internal::Double(d).IsNan()) {
353 PutReserve(*os_, 3);
354 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
355 return true;
356 }
357 if (internal::Double(d).Sign()) {
358 PutReserve(*os_, 9);
359 PutUnsafe(*os_, '-');
360 }
361 else
362 PutReserve(*os_, 8);
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');
365 return true;
366 }
367
368 char buffer[25];
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));
373 return true;
374 }
375
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
384 Z16, Z16, // 30~4F
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
387#undef Z16
388 };
389
390 if (TargetEncoding::supportUnicode)
391 PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
392 else
393 PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
394
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) {
400 // Unicode escaping
401 unsigned codepoint;
402 if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
403 return false;
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]);
411 }
412 else {
413 RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
414 // Surrogate pair
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]);
428 }
429 }
430 else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
431 is.Take();
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]);
439 }
440 }
441 else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
442 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
443 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
444 return false;
445 }
446 PutUnsafe(*os_, '\"');
447 return true;
448 }
449
450 bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
451 return RAPIDJSON_LIKELY(is.Tell() < length);
452 }
453
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; }
458
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_))))
467 return false;
468 }
469 return true;
470 }
471
472 void Prefix(Type type) {
473 (void)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) {
477 if (level->inArray)
478 os_->Put(','); // add comma if it is not the first element in array
479 else // in object
480 os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
481 }
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
484 level->valueCount++;
485 }
486 else {
487 RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
488 hasRoot_ = true;
489 }
490 }
491
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
495 Flush();
496 return ret;
497 }
498
499 OutputStream* os_;
500 internal::Stack<StackAllocator> level_stack_;
501 int maxDecimalPlaces_;
502 bool hasRoot_;
503
504private:
505 // Prohibit copy constructor & assignment operator.
506 Writer(const Writer&);
507 Writer& operator=(const Writer&);
508};
509
510// Full specialization for StringStream to prevent memory copying
511
512template<>
513inline 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)));
517 return true;
518}
519
520template<>
521inline 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)));
525 return true;
526}
527
528template<>
529inline 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)));
533 return true;
534}
535
536template<>
537inline 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)));
541 return true;
542}
543
544template<>
545inline 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))
549 return false;
550 if (internal::Double(d).IsNan()) {
551 PutReserve(*os_, 3);
552 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
553 return true;
554 }
555 if (internal::Double(d).Sign()) {
556 PutReserve(*os_, 9);
557 PutUnsafe(*os_, '-');
558 }
559 else
560 PutReserve(*os_, 8);
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');
563 return true;
564 }
565
566 char *buffer = os_->Push(25);
567 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
568 os_->Pop(static_cast<size_t>(25 - (end - buffer)));
569 return true;
570}
571
572#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
573template<>
574inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
575 if (length < 16)
576 return RAPIDJSON_LIKELY(is.Tell() < length);
577
578 if (!RAPIDJSON_LIKELY(is.Tell() < length))
579 return false;
580
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)
586 return true;
587
588 while (p != nextAligned)
589 if (*p < 0x20 || *p == '\"' || *p == '\\') {
590 is.src_ = p;
591 return RAPIDJSON_LIKELY(is.Tell() < length);
592 }
593 else
594 os_->PutUnsafe(*p++);
595
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]));
603
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
612 SizeType len;
613#ifdef _MSC_VER // Find the index of first escaped
614 unsigned long offset;
615 _BitScanForward(&offset, r);
616 len = offset;
617#else
618 len = static_cast<SizeType>(__builtin_ffs(r) - 1);
619#endif
620 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
621 for (size_t i = 0; i < len; i++)
622 q[i] = p[i];
623
624 p += len;
625 break;
626 }
627 _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
628 }
629
630 is.src_ = p;
631 return RAPIDJSON_LIKELY(is.Tell() < length);
632}
633#elif defined(RAPIDJSON_NEON)
634template<>
635inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
636 if (length < 16)
637 return RAPIDJSON_LIKELY(is.Tell() < length);
638
639 if (!RAPIDJSON_LIKELY(is.Tell() < length))
640 return false;
641
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)
647 return true;
648
649 while (p != nextAligned)
650 if (*p < 0x20 || *p == '\"' || *p == '\\') {
651 is.src_ = p;
652 return RAPIDJSON_LIKELY(is.Tell() < length);
653 }
654 else
655 os_->PutUnsafe(*p++);
656
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);
662
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));
669
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
673
674 SizeType len = 0;
675 bool escaped = false;
676 if (low == 0) {
677 if (high != 0) {
678 unsigned lz = (unsigned)__builtin_clzll(high);
679 len = 8 + (lz >> 3);
680 escaped = true;
681 }
682 } else {
683 unsigned lz = (unsigned)__builtin_clzll(low);
684 len = lz >> 3;
685 escaped = true;
686 }
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++)
690 q[i] = p[i];
691
692 p += len;
693 break;
694 }
695 vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
696 }
697
698 is.src_ = p;
699 return RAPIDJSON_LIKELY(is.Tell() < length);
700}
701#endif // RAPIDJSON_NEON
702
703RAPIDJSON_NAMESPACE_END
704
705#if defined(_MSC_VER) || defined(__clang__)
706RAPIDJSON_DIAG_POP
707#endif
708
709#endif // RAPIDJSON_RAPIDJSON_H_
710