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

source code of qt3d/src/3rdparty/assimp/contrib/rapidjson/include/rapidjson/writer.h