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.
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__
41 RAPIDJSON_DIAG_PUSH
42 RAPIDJSON_DIAG_OFF(padded)
43 RAPIDJSON_DIAG_OFF(unreachable-code)
44 RAPIDJSON_DIAG_OFF(c++98-compat)
45 #elif defined(_MSC_VER)
46 RAPIDJSON_DIAG_PUSH
47 RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
48 #endif
49 
50 RAPIDJSON_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
66 enum WriteFlag {
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  kWriteNanAndInfNullFlag = 4, //!< Allow writing of Infinity, -Infinity and NaN as null.
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 */
90 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
91 class Writer {
92 public:
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 
287  static const size_t kDefaultLevelDepth = 32;
288 
289 protected:
290  //! Information for each nested level
291  struct Level {
292  Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
293  size_t valueCount; //!< number of values in this level
294  bool inArray; //!< true if in array, otherwise in object
295  };
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) && !(writeFlags & kWriteNanAndInfNullFlag))
353  return false;
354  if (writeFlags & kWriteNanAndInfNullFlag) {
355  PutReserve(*os_, 4);
356  PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
357  return true;
358  }
359  if (internal::Double(d).IsNan()) {
360  PutReserve(*os_, 3);
361  PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
362  return true;
363  }
364  if (internal::Double(d).Sign()) {
365  PutReserve(*os_, 9);
366  PutUnsafe(*os_, '-');
367  }
368  else
369  PutReserve(*os_, 8);
370  PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
371  PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
372  return true;
373  }
374 
375  char buffer[25];
376  char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
377  PutReserve(*os_, static_cast<size_t>(end - buffer));
378  for (char* p = buffer; p != end; ++p)
379  PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
380  return true;
381  }
382 
383  bool WriteString(const Ch* str, SizeType length) {
384  static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
385  static const char escape[256] = {
386 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
387  //0 1 2 3 4 5 6 7 8 9 A B C D E F
388  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
389  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
390  0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
391  Z16, Z16, // 30~4F
392  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
393  Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
394 #undef Z16
395  };
396 
397  if (TargetEncoding::supportUnicode)
398  PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
399  else
400  PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
401 
402  PutUnsafe(*os_, '\"');
403  GenericStringStream<SourceEncoding> is(str);
404  while (ScanWriteUnescapedString(is, length)) {
405  const Ch c = is.Peek();
406  if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
407  // Unicode escaping
408  unsigned codepoint;
409  if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
410  return false;
411  PutUnsafe(*os_, '\\');
412  PutUnsafe(*os_, 'u');
413  if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
414  PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
415  PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
416  PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
417  PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
418  }
419  else {
420  RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
421  // Surrogate pair
422  unsigned s = codepoint - 0x010000;
423  unsigned lead = (s >> 10) + 0xD800;
424  unsigned trail = (s & 0x3FF) + 0xDC00;
425  PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
426  PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
427  PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
428  PutUnsafe(*os_, hexDigits[(lead ) & 15]);
429  PutUnsafe(*os_, '\\');
430  PutUnsafe(*os_, 'u');
431  PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
432  PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
433  PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
434  PutUnsafe(*os_, hexDigits[(trail ) & 15]);
435  }
436  }
437  else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
438  is.Take();
439  PutUnsafe(*os_, '\\');
440  PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
441  if (escape[static_cast<unsigned char>(c)] == 'u') {
442  PutUnsafe(*os_, '0');
443  PutUnsafe(*os_, '0');
444  PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
445  PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
446  }
447  }
448  else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
449  Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
450  Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
451  return false;
452  }
453  PutUnsafe(*os_, '\"');
454  return true;
455  }
456 
457  bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
458  return RAPIDJSON_LIKELY(is.Tell() < length);
459  }
460 
461  bool WriteStartObject() { os_->Put('{'); return true; }
462  bool WriteEndObject() { os_->Put('}'); return true; }
463  bool WriteStartArray() { os_->Put('['); return true; }
464  bool WriteEndArray() { os_->Put(']'); return true; }
465 
466  bool WriteRawValue(const Ch* json, size_t length) {
467  PutReserve(*os_, length);
468  GenericStringStream<SourceEncoding> is(json);
469  while (RAPIDJSON_LIKELY(is.Tell() < length)) {
470  RAPIDJSON_ASSERT(is.Peek() != '\0');
471  if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
472  Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
473  Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
474  return false;
475  }
476  return true;
477  }
478 
479  void Prefix(Type type) {
480  (void)type;
481  if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
482  Level* level = level_stack_.template Top<Level>();
483  if (level->valueCount > 0) {
484  if (level->inArray)
485  os_->Put(','); // add comma if it is not the first element in array
486  else // in object
487  os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
488  }
489  if (!level->inArray && level->valueCount % 2 == 0)
490  RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
491  level->valueCount++;
492  }
493  else {
494  RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
495  hasRoot_ = true;
496  }
497  }
498 
499  // Flush the value if it is the top level one.
500  bool EndValue(bool ret) {
501  if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
502  Flush();
503  return ret;
504  }
505 
506  OutputStream* os_;
507  internal::Stack<StackAllocator> level_stack_;
508  int maxDecimalPlaces_;
509  bool hasRoot_;
510 
511 private:
512  // Prohibit copy constructor & assignment operator.
513  Writer(const Writer&);
514  Writer& operator=(const Writer&);
515 };
516 
517 // Full specialization for StringStream to prevent memory copying
518 
519 template<>
520 inline bool Writer<StringBuffer>::WriteInt(int i) {
521  char *buffer = os_->Push(11);
522  const char* end = internal::i32toa(i, buffer);
523  os_->Pop(static_cast<size_t>(11 - (end - buffer)));
524  return true;
525 }
526 
527 template<>
528 inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
529  char *buffer = os_->Push(10);
530  const char* end = internal::u32toa(u, buffer);
531  os_->Pop(static_cast<size_t>(10 - (end - buffer)));
532  return true;
533 }
534 
535 template<>
536 inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
537  char *buffer = os_->Push(21);
538  const char* end = internal::i64toa(i64, buffer);
539  os_->Pop(static_cast<size_t>(21 - (end - buffer)));
540  return true;
541 }
542 
543 template<>
544 inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
545  char *buffer = os_->Push(20);
546  const char* end = internal::u64toa(u, buffer);
547  os_->Pop(static_cast<size_t>(20 - (end - buffer)));
548  return true;
549 }
550 
551 template<>
552 inline bool Writer<StringBuffer>::WriteDouble(double d) {
553  if (internal::Double(d).IsNanOrInf()) {
554  // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
555  if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
556  return false;
557  if (kWriteDefaultFlags & kWriteNanAndInfNullFlag) {
558  PutReserve(*os_, 4);
559  PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
560  return true;
561  }
562  if (internal::Double(d).IsNan()) {
563  PutReserve(*os_, 3);
564  PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
565  return true;
566  }
567  if (internal::Double(d).Sign()) {
568  PutReserve(*os_, 9);
569  PutUnsafe(*os_, '-');
570  }
571  else
572  PutReserve(*os_, 8);
573  PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
574  PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
575  return true;
576  }
577 
578  char *buffer = os_->Push(25);
579  char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
580  os_->Pop(static_cast<size_t>(25 - (end - buffer)));
581  return true;
582 }
583 
584 #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
585 template<>
586 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
587  if (length < 16)
588  return RAPIDJSON_LIKELY(is.Tell() < length);
589 
590  if (!RAPIDJSON_LIKELY(is.Tell() < length))
591  return false;
592 
593  const char* p = is.src_;
594  const char* end = is.head_ + length;
595  const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
596  const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
597  if (nextAligned > end)
598  return true;
599 
600  while (p != nextAligned)
601  if (*p < 0x20 || *p == '\"' || *p == '\\') {
602  is.src_ = p;
603  return RAPIDJSON_LIKELY(is.Tell() < length);
604  }
605  else
606  os_->PutUnsafe(*p++);
607 
608  // The rest of string using SIMD
609  static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
610  static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
611  static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
612  const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
613  const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
614  const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
615 
616  for (; p != endAligned; p += 16) {
617  const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
618  const __m128i t1 = _mm_cmpeq_epi8(s, dq);
619  const __m128i t2 = _mm_cmpeq_epi8(s, bs);
620  const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
621  const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
622  unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
623  if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
624  SizeType len;
625 #ifdef _MSC_VER // Find the index of first escaped
626  unsigned long offset;
627  _BitScanForward(&offset, r);
628  len = offset;
629 #else
630  len = static_cast<SizeType>(__builtin_ffs(r) - 1);
631 #endif
632  char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
633  for (size_t i = 0; i < len; i++)
634  q[i] = p[i];
635 
636  p += len;
637  break;
638  }
639  _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
640  }
641 
642  is.src_ = p;
643  return RAPIDJSON_LIKELY(is.Tell() < length);
644 }
645 #elif defined(RAPIDJSON_NEON)
646 template<>
647 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
648  if (length < 16)
649  return RAPIDJSON_LIKELY(is.Tell() < length);
650 
651  if (!RAPIDJSON_LIKELY(is.Tell() < length))
652  return false;
653 
654  const char* p = is.src_;
655  const char* end = is.head_ + length;
656  const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
657  const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
658  if (nextAligned > end)
659  return true;
660 
661  while (p != nextAligned)
662  if (*p < 0x20 || *p == '\"' || *p == '\\') {
663  is.src_ = p;
664  return RAPIDJSON_LIKELY(is.Tell() < length);
665  }
666  else
667  os_->PutUnsafe(*p++);
668 
669  // The rest of string using SIMD
670  const uint8x16_t s0 = vmovq_n_u8('"');
671  const uint8x16_t s1 = vmovq_n_u8('\\');
672  const uint8x16_t s2 = vmovq_n_u8('\b');
673  const uint8x16_t s3 = vmovq_n_u8(32);
674 
675  for (; p != endAligned; p += 16) {
676  const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
677  uint8x16_t x = vceqq_u8(s, s0);
678  x = vorrq_u8(x, vceqq_u8(s, s1));
679  x = vorrq_u8(x, vceqq_u8(s, s2));
680  x = vorrq_u8(x, vcltq_u8(s, s3));
681 
682  x = vrev64q_u8(x); // Rev in 64
683  uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
684  uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
685 
686  SizeType len = 0;
687  bool escaped = false;
688  if (low == 0) {
689  if (high != 0) {
690  uint32_t lz = internal::clzll(high);
691  len = 8 + (lz >> 3);
692  escaped = true;
693  }
694  } else {
695  uint32_t lz = internal::clzll(low);
696  len = lz >> 3;
697  escaped = true;
698  }
699  if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
700  char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
701  for (size_t i = 0; i < len; i++)
702  q[i] = p[i];
703 
704  p += len;
705  break;
706  }
707  vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
708  }
709 
710  is.src_ = p;
711  return RAPIDJSON_LIKELY(is.Tell() < length);
712 }
713 #endif // RAPIDJSON_NEON
714 
715 RAPIDJSON_NAMESPACE_END
716 
717 #if defined(_MSC_VER) || defined(__clang__)
718 RAPIDJSON_DIAG_POP
719 #endif
720 
721 #endif // RAPIDJSON_RAPIDJSON_H_
true
Definition: rapidjson.h:732
bool inArray
true if in array, otherwise in object
Definition: writer.h:294
void SetMaxDecimalPlaces(int maxDecimalPlaces)
Sets the maximum number of decimal places for double output.
Definition: writer.h:174
No flags are set.
Definition: writer.h:67
Validate encoding of JSON strings.
Definition: writer.h:68
void PutReserve(Stream &stream, size_t count)
Reserve n characters for writing to a stream.
Definition: stream.h:84
unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:415
bool String(const Ch *const &str)
Simpler but slower overload.
Definition: writer.h:260
WriteFlag
Combination of writeFlags.
Definition: writer.h:66
false
Definition: rapidjson.h:731
bool RawValue(const Ch *json, size_t length, Type type)
Write a raw JSON value.
Definition: writer.h:273
#define RAPIDJSON_LIKELY(x)
Compiler branching hint for expression with high probability to be true.
Definition: rapidjson.h:494
Information for each nested level.
Definition: writer.h:291
size_t valueCount
number of values in this level
Definition: writer.h:293
Type
Type of JSON value.
Definition: rapidjson.h:729
object
Definition: rapidjson.h:733
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition: rapidjson.h:507
array
Definition: rapidjson.h:734
JSON writer.
Definition: fwd.h:95
null
Definition: rapidjson.h:730
string
Definition: rapidjson.h:735
Allow writing of Infinity, -Infinity and NaN as null.
Definition: writer.h:70
Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS. ...
Definition: writer.h:71
void Flush()
Flush the output stream.
Definition: writer.h:283
#define RAPIDJSON_WRITE_DEFAULT_FLAGS
User-defined kWriteDefaultFlags definition.
Definition: writer.h:62
bool IsComplete() const
Checks whether the output is a complete JSON.
Definition: writer.h:145
bool Double(double d)
Writes the given double value to the stream.
Definition: writer.h:195
void PutUnsafe(Stream &stream, typename Stream::Ch c)
Write character to a stream, presuming buffer is reserved.
Definition: stream.h:91
Writer(OutputStream &os, StackAllocator *stackAllocator=0, size_t levelDepth=kDefaultLevelDepth)
Constructor.
Definition: writer.h:103
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:437
void Reset(OutputStream &os)
Reset the writer with a new stream.
Definition: writer.h:135
number
Definition: rapidjson.h:736
Allow writing of Infinity, -Infinity and NaN.
Definition: writer.h:69