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