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/stack.h"
20#include "internal/strfunc.h"
21#include "internal/dtoa.h"
22#include "internal/itoa.h"
23#include "stringbuffer.h"
24#include <new> // placement new
25
26#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
27#include <intrin.h>
28#pragma intrinsic(_BitScanForward)
29#endif
30#ifdef RAPIDJSON_SSE42
31#include <nmmintrin.h>
32#elif defined(RAPIDJSON_SSE2)
33#include <emmintrin.h>
34#endif
35
36#ifdef _MSC_VER
37RAPIDJSON_DIAG_PUSH
38RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
39#endif
40
41#ifdef __clang__
42RAPIDJSON_DIAG_PUSH
43RAPIDJSON_DIAG_OFF(padded)
44RAPIDJSON_DIAG_OFF(unreachable-code)
45#endif
46
47RAPIDJSON_NAMESPACE_BEGIN
48
49///////////////////////////////////////////////////////////////////////////////
50// WriteFlag
51
52/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
53 \ingroup RAPIDJSON_CONFIG
54 \brief User-defined kWriteDefaultFlags definition.
55
56 User can define this as any \c WriteFlag combinations.
57*/
58#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
59#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
60#endif
61
62//! Combination of writeFlags
63enum WriteFlag {
64 kWriteNoFlags = 0, //!< No flags are set.
65 kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
66 kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
67 kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
68};
69
70//! JSON writer
71/*! Writer implements the concept Handler.
72 It generates JSON text by events to an output os.
73
74 User may programmatically calls the functions of a writer to generate JSON text.
75
76 On the other side, a writer can also be passed to objects that generates events,
77
78 for example Reader::Parse() and Document::Accept().
79
80 \tparam OutputStream Type of output stream.
81 \tparam SourceEncoding Encoding of source string.
82 \tparam TargetEncoding Encoding of output stream.
83 \tparam StackAllocator Type of allocator for allocating memory of stack.
84 \note implements Handler concept
85*/
86template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
87class Writer {
88public:
89 typedef typename SourceEncoding::Ch Ch;
90
91 static const int kDefaultMaxDecimalPlaces = 324;
92
93 //! Constructor
94 /*! \param os Output stream.
95 \param stackAllocator User supplied allocator. If it is null, it will create a private one.
96 \param levelDepth Initial capacity of stack.
97 */
98 explicit
99 Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
100 os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
101
102 explicit
103 Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
104 os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
105
106 //! Reset the writer with a new stream.
107 /*!
108 This function reset the writer with a new stream and default settings,
109 in order to make a Writer object reusable for output multiple JSONs.
110
111 \param os New output stream.
112 \code
113 Writer<OutputStream> writer(os1);
114 writer.StartObject();
115 // ...
116 writer.EndObject();
117
118 writer.Reset(os2);
119 writer.StartObject();
120 // ...
121 writer.EndObject();
122 \endcode
123 */
124 void Reset(OutputStream& os) {
125 os_ = &os;
126 hasRoot_ = false;
127 level_stack_.Clear();
128 }
129
130 //! Checks whether the output is a complete JSON.
131 /*!
132 A complete JSON has a complete root object or array.
133 */
134 bool IsComplete() const {
135 return hasRoot_ && level_stack_.Empty();
136 }
137
138 int GetMaxDecimalPlaces() const {
139 return maxDecimalPlaces_;
140 }
141
142 //! Sets the maximum number of decimal places for double output.
143 /*!
144 This setting truncates the output with specified number of decimal places.
145
146 For example,
147
148 \code
149 writer.SetMaxDecimalPlaces(3);
150 writer.StartArray();
151 writer.Double(0.12345); // "0.123"
152 writer.Double(0.0001); // "0.0"
153 writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
154 writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
155 writer.EndArray();
156 \endcode
157
158 The default setting does not truncate any decimal places. You can restore to this setting by calling
159 \code
160 writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
161 \endcode
162 */
163 void SetMaxDecimalPlaces(int maxDecimalPlaces) {
164 maxDecimalPlaces_ = maxDecimalPlaces;
165 }
166
167 /*!@name Implementation of Handler
168 \see Handler
169 */
170 //@{
171
172 bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
173 bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
174 bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
175 bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
176 bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
177 bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
178
179 //! Writes the given \c double value to the stream
180 /*!
181 \param d The value to be written.
182 \return Whether it is succeed.
183 */
184 bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
185
186 bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
187 (void)copy;
188 Prefix(kNumberType);
189 return EndValue(WriteString(str, length));
190 }
191
192 bool String(const Ch* str, SizeType length, bool copy = false) {
193 (void)copy;
194 Prefix(kStringType);
195 return EndValue(WriteString(str, length));
196 }
197
198#if RAPIDJSON_HAS_STDSTRING
199 bool String(const std::basic_string<Ch>& str) {
200 return String(str.data(), SizeType(str.size()));
201 }
202#endif
203
204 bool StartObject() {
205 Prefix(kObjectType);
206 new (level_stack_.template Push<Level>()) Level(false);
207 return WriteStartObject();
208 }
209
210 bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
211
212 bool EndObject(SizeType memberCount = 0) {
213 (void)memberCount;
214 RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
215 RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
216 level_stack_.template Pop<Level>(1);
217 return EndValue(WriteEndObject());
218 }
219
220 bool StartArray() {
221 Prefix(kArrayType);
222 new (level_stack_.template Push<Level>()) Level(true);
223 return WriteStartArray();
224 }
225
226 bool EndArray(SizeType elementCount = 0) {
227 (void)elementCount;
228 RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
229 RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
230 level_stack_.template Pop<Level>(1);
231 return EndValue(WriteEndArray());
232 }
233 //@}
234
235 /*! @name Convenience extensions */
236 //@{
237
238 //! Simpler but slower overload.
239 bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
240 bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
241
242 //@}
243
244 //! Write a raw JSON value.
245 /*!
246 For user to write a stringified JSON as a value.
247
248 \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
249 \param length Length of the json.
250 \param type Type of the root of json.
251 */
252 bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }
253
254protected:
255 //! Information for each nested level
256 struct Level {
257 Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
258 size_t valueCount; //!< number of values in this level
259 bool inArray; //!< true if in array, otherwise in object
260 };
261
262 static const size_t kDefaultLevelDepth = 32;
263
264 bool WriteNull() {
265 PutReserve(*os_, 4);
266 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
267 }
268
269 bool WriteBool(bool b) {
270 if (b) {
271 PutReserve(*os_, 4);
272 PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
273 }
274 else {
275 PutReserve(*os_, 5);
276 PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
277 }
278 return true;
279 }
280
281 bool WriteInt(int i) {
282 char buffer[11];
283 const char* end = internal::i32toa(i, buffer);
284 PutReserve(*os_, static_cast<size_t>(end - buffer));
285 for (const char* p = buffer; p != end; ++p)
286 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
287 return true;
288 }
289
290 bool WriteUint(unsigned u) {
291 char buffer[10];
292 const char* end = internal::u32toa(u, buffer);
293 PutReserve(*os_, static_cast<size_t>(end - buffer));
294 for (const char* p = buffer; p != end; ++p)
295 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
296 return true;
297 }
298
299 bool WriteInt64(int64_t i64) {
300 char buffer[21];
301 const char* end = internal::i64toa(i64, buffer);
302 PutReserve(*os_, static_cast<size_t>(end - buffer));
303 for (const char* p = buffer; p != end; ++p)
304 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
305 return true;
306 }
307
308 bool WriteUint64(uint64_t u64) {
309 char buffer[20];
310 char* end = internal::u64toa(u64, buffer);
311 PutReserve(*os_, static_cast<size_t>(end - buffer));
312 for (char* p = buffer; p != end; ++p)
313 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
314 return true;
315 }
316
317 bool WriteDouble(double d) {
318 if (internal::Double(d).IsNanOrInf()) {
319 if (!(writeFlags & kWriteNanAndInfFlag))
320 return false;
321 if (internal::Double(d).IsNan()) {
322 PutReserve(*os_, 3);
323 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
324 return true;
325 }
326 if (internal::Double(d).Sign()) {
327 PutReserve(*os_, 9);
328 PutUnsafe(*os_, '-');
329 }
330 else
331 PutReserve(*os_, 8);
332 PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
333 PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
334 return true;
335 }
336
337 char buffer[25];
338 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
339 PutReserve(*os_, static_cast<size_t>(end - buffer));
340 for (char* p = buffer; p != end; ++p)
341 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
342 return true;
343 }
344
345 bool WriteString(const Ch* str, SizeType length) {
346 static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
347 static const char escape[256] = {
348#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
349 //0 1 2 3 4 5 6 7 8 9 A B C D E F
350 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
351 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
352 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
353 Z16, Z16, // 30~4F
354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
355 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
356#undef Z16
357 };
358
359 if (TargetEncoding::supportUnicode)
360 PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
361 else
362 PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
363
364 PutUnsafe(*os_, '\"');
365 GenericStringStream<SourceEncoding> is(str);
366 while (ScanWriteUnescapedString(is, length)) {
367 const Ch c = is.Peek();
368 if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
369 // Unicode escaping
370 unsigned codepoint;
371 if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
372 return false;
373 PutUnsafe(*os_, '\\');
374 PutUnsafe(*os_, 'u');
375 if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
376 PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
377 PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
378 PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
379 PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
380 }
381 else {
382 RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
383 // Surrogate pair
384 unsigned s = codepoint - 0x010000;
385 unsigned lead = (s >> 10) + 0xD800;
386 unsigned trail = (s & 0x3FF) + 0xDC00;
387 PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
388 PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
389 PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
390 PutUnsafe(*os_, hexDigits[(lead ) & 15]);
391 PutUnsafe(*os_, '\\');
392 PutUnsafe(*os_, 'u');
393 PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
394 PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
395 PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
396 PutUnsafe(*os_, hexDigits[(trail ) & 15]);
397 }
398 }
399 else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
400 is.Take();
401 PutUnsafe(*os_, '\\');
402 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
403 if (escape[static_cast<unsigned char>(c)] == 'u') {
404 PutUnsafe(*os_, '0');
405 PutUnsafe(*os_, '0');
406 PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
407 PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
408 }
409 }
410 else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
411 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
412 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
413 return false;
414 }
415 PutUnsafe(*os_, '\"');
416 return true;
417 }
418
419 bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
420 return RAPIDJSON_LIKELY(is.Tell() < length);
421 }
422
423 bool WriteStartObject() { os_->Put('{'); return true; }
424 bool WriteEndObject() { os_->Put('}'); return true; }
425 bool WriteStartArray() { os_->Put('['); return true; }
426 bool WriteEndArray() { os_->Put(']'); return true; }
427
428 bool WriteRawValue(const Ch* json, size_t length) {
429 PutReserve(*os_, length);
430 for (size_t i = 0; i < length; i++) {
431 RAPIDJSON_ASSERT(json[i] != '\0');
432 PutUnsafe(*os_, json[i]);
433 }
434 return true;
435 }
436
437 void Prefix(Type type) {
438 (void)type;
439 if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
440 Level* level = level_stack_.template Top<Level>();
441 if (level->valueCount > 0) {
442 if (level->inArray)
443 os_->Put(','); // add comma if it is not the first element in array
444 else // in object
445 os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
446 }
447 if (!level->inArray && level->valueCount % 2 == 0)
448 RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
449 level->valueCount++;
450 }
451 else {
452 RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
453 hasRoot_ = true;
454 }
455 }
456
457 // Flush the value if it is the top level one.
458 bool EndValue(bool ret) {
459 if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
460 os_->Flush();
461 return ret;
462 }
463
464 OutputStream* os_;
465 internal::Stack<StackAllocator> level_stack_;
466 int maxDecimalPlaces_;
467 bool hasRoot_;
468
469private:
470 // Prohibit copy constructor & assignment operator.
471 Writer(const Writer&);
472 Writer& operator=(const Writer&);
473};
474
475// Full specialization for StringStream to prevent memory copying
476
477template<>
478inline bool Writer<StringBuffer>::WriteInt(int i) {
479 char *buffer = os_->Push(11);
480 const char* end = internal::i32toa(i, buffer);
481 os_->Pop(static_cast<size_t>(11 - (end - buffer)));
482 return true;
483}
484
485template<>
486inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
487 char *buffer = os_->Push(10);
488 const char* end = internal::u32toa(u, buffer);
489 os_->Pop(static_cast<size_t>(10 - (end - buffer)));
490 return true;
491}
492
493template<>
494inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
495 char *buffer = os_->Push(21);
496 const char* end = internal::i64toa(i64, buffer);
497 os_->Pop(static_cast<size_t>(21 - (end - buffer)));
498 return true;
499}
500
501template<>
502inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
503 char *buffer = os_->Push(20);
504 const char* end = internal::u64toa(u, buffer);
505 os_->Pop(static_cast<size_t>(20 - (end - buffer)));
506 return true;
507}
508
509template<>
510inline bool Writer<StringBuffer>::WriteDouble(double d) {
511 if (internal::Double(d).IsNanOrInf()) {
512 // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
513 if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
514 return false;
515 if (internal::Double(d).IsNan()) {
516 PutReserve(*os_, 3);
517 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
518 return true;
519 }
520 if (internal::Double(d).Sign()) {
521 PutReserve(*os_, 9);
522 PutUnsafe(*os_, '-');
523 }
524 else
525 PutReserve(*os_, 8);
526 PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
527 PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
528 return true;
529 }
530
531 char *buffer = os_->Push(25);
532 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
533 os_->Pop(static_cast<size_t>(25 - (end - buffer)));
534 return true;
535}
536
537#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
538template<>
539inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
540 if (length < 16)
541 return RAPIDJSON_LIKELY(is.Tell() < length);
542
543 if (!RAPIDJSON_LIKELY(is.Tell() < length))
544 return false;
545
546 const char* p = is.src_;
547 const char* end = is.head_ + length;
548 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
549 const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
550 if (nextAligned > end)
551 return true;
552
553 while (p != nextAligned)
554 if (*p < 0x20 || *p == '\"' || *p == '\\') {
555 is.src_ = p;
556 return RAPIDJSON_LIKELY(is.Tell() < length);
557 }
558 else
559 os_->PutUnsafe(*p++);
560
561 // The rest of string using SIMD
562 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
563 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
564 static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
565 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
566 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
567 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
568
569 for (; p != endAligned; p += 16) {
570 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
571 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
572 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
573 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
574 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
575 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
576 if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
577 SizeType len;
578#ifdef _MSC_VER // Find the index of first escaped
579 unsigned long offset;
580 _BitScanForward(&offset, r);
581 len = offset;
582#else
583 len = static_cast<SizeType>(__builtin_ffs(r) - 1);
584#endif
585 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
586 for (size_t i = 0; i < len; i++)
587 q[i] = p[i];
588
589 p += len;
590 break;
591 }
592 _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
593 }
594
595 is.src_ = p;
596 return RAPIDJSON_LIKELY(is.Tell() < length);
597}
598#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
599
600RAPIDJSON_NAMESPACE_END
601
602#ifdef _MSC_VER
603RAPIDJSON_DIAG_POP
604#endif
605
606#ifdef __clang__
607RAPIDJSON_DIAG_POP
608#endif
609
610#endif // RAPIDJSON_RAPIDJSON_H_
611