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__
40 RAPIDJSON_DIAG_PUSH
41 RAPIDJSON_DIAG_OFF(padded)
42 RAPIDJSON_DIAG_OFF(unreachable-code)
43 RAPIDJSON_DIAG_OFF(c++98-compat)
44 #elif defined(_MSC_VER)
45 RAPIDJSON_DIAG_PUSH
46 RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
47 #endif
48
49 RAPIDJSON_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
65 enum 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 */
88 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
89 class Writer {
90 public:
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
Writer(Writer && rhs)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 */
Reset(OutputStream & os)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 */
IsComplete()143 bool IsComplete() const {
144 return hasRoot_ && level_stack_.Empty();
145 }
146
GetMaxDecimalPlaces()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 */
SetMaxDecimalPlaces(int maxDecimalPlaces)172 void SetMaxDecimalPlaces(int maxDecimalPlaces) {
173 maxDecimalPlaces_ = maxDecimalPlaces;
174 }
175
176 /*!@name Implementation of Handler
177 \see Handler
178 */
179 //@{
180
Null()181 bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
Bool(bool b)182 bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
Int(int i)183 bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
Uint(unsigned u)184 bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
Int64(int64_t i64)185 bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
Uint64(uint64_t u64)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 */
Double(double d)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
String(const std::basic_string<Ch> & str)210 bool String(const std::basic_string<Ch>& str) {
211 return String(str.data(), SizeType(str.size()));
212 }
213 #endif
214
StartObject()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
Key(const std::basic_string<Ch> & str)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
StartArray()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.
String(const Ch * const & str)258 bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
Key(const Ch * const & 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 */
RawValue(const Ch * json,size_t length,Type type)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 */
Flush()281 void Flush() {
282 os_->Flush();
283 }
284
285 protected:
286 //! Information for each nested level
287 struct Level {
LevelLevel288 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
WriteNull()295 bool WriteNull() {
296 PutReserve(*os_, 4);
297 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
298 }
299
WriteBool(bool b)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
WriteInt(int i)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
WriteUint(unsigned u)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
WriteInt64(int64_t i64)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
WriteUint64(uint64_t u64)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
WriteDouble(double d)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
WriteString(const Ch * str,SizeType length)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
ScanWriteUnescapedString(GenericStringStream<SourceEncoding> & is,size_t length)450 bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
451 return RAPIDJSON_LIKELY(is.Tell() < length);
452 }
453
WriteStartObject()454 bool WriteStartObject() { os_->Put('{'); return true; }
WriteEndObject()455 bool WriteEndObject() { os_->Put('}'); return true; }
WriteStartArray()456 bool WriteStartArray() { os_->Put('['); return true; }
WriteEndArray()457 bool WriteEndArray() { os_->Put(']'); return true; }
458
WriteRawValue(const Ch * json,size_t length)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 const Ch c = is.Peek();
464 RAPIDJSON_ASSERT(c != '\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
Prefix(Type type)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.
EndValue(bool ret)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
505 private:
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
513 template<>
WriteInt(int i)514 inline 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
521 template<>
WriteUint(unsigned u)522 inline 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
529 template<>
WriteInt64(int64_t i64)530 inline 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
537 template<>
WriteUint64(uint64_t u)538 inline 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
545 template<>
WriteDouble(double d)546 inline 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)
574 template<>
ScanWriteUnescapedString(StringStream & is,size_t length)575 inline 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)
635 template<>
ScanWriteUnescapedString(StringStream & is,size_t length)636 inline 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(reinterpret_cast<uint64x2_t>(x), 0); // extract
673 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
674
675 SizeType len = 0;
676 bool escaped = false;
677 if (low == 0) {
678 if (high != 0) {
679 unsigned lz = (unsigned)__builtin_clzll(high);
680 len = 8 + (lz >> 3);
681 escaped = true;
682 }
683 } else {
684 unsigned lz = (unsigned)__builtin_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
704 RAPIDJSON_NAMESPACE_END
705
706 #if defined(_MSC_VER) || defined(__clang__)
707 RAPIDJSON_DIAG_POP
708 #endif
709
710 #endif // RAPIDJSON_RAPIDJSON_H_
711