COSC345-Eventures
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 
51 
53 // WriteFlag
54 
61 #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
62 #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
63 #endif
64 
66 enum WriteFlag {
67  kWriteNoFlags = 0,
68  kWriteValidateEncodingFlag = 1,
69  kWriteNanAndInfFlag = 2,
70  kWriteNanAndInfNullFlag = 4,
71  kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS
72 };
73 
75 
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 
98 
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 
118 
135  void Reset(OutputStream& os) {
136  os_ = &os;
137  hasRoot_ = false;
138  level_stack_.Clear();
139  }
140 
142 
145  bool IsComplete() const {
146  return hasRoot_ && level_stack_.Empty();
147  }
148 
149  int GetMaxDecimalPlaces() const {
150  return maxDecimalPlaces_;
151  }
152 
154 
174  void SetMaxDecimalPlaces(int maxDecimalPlaces) {
175  maxDecimalPlaces_ = maxDecimalPlaces;
176  }
177 
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 
191 
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  }
255 
258 
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 
264 
266 
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 
280 
283  void Flush() {
284  os_->Flush();
285  }
286 
287  static const size_t kDefaultLevelDepth = 32;
288 
289 protected:
291  struct Level {
292  Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
293  size_t valueCount;
294  bool inArray;
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))
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_, '\"');
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 ?
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);
469  while (RAPIDJSON_LIKELY(is.Tell() < length)) {
470  RAPIDJSON_ASSERT(is.Peek() != '\0');
471  if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
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 
716 
717 #if defined(_MSC_VER) || defined(__clang__)
718 RAPIDJSON_DIAG_POP
719 #endif
720 
721 #endif // RAPIDJSON_RAPIDJSON_H_
Encoding conversion.
Definition: encodings.h:658
size_t valueCount
number of values in this level
Definition: writer.h:293
void Flush()
Flush the output stream.
Definition: writer.h:283
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:415
bool inArray
true if in array, otherwise in object
Definition: writer.h:294
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:437
bool String(const Ch *const &str)
Simpler but slower overload.
Definition: writer.h:260
JSON writer.
Definition: fwd.h:95
object
Definition: rapidjson.h:733
Read-only string stream.
Definition: fwd.h:47
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
array
Definition: rapidjson.h:734
const Ch * src_
Current read position.
Definition: stream.h:168
bool RawValue(const Ch *json, size_t length, Type type)
Write a raw JSON value.
Definition: writer.h:273
false
Definition: rapidjson.h:731
bool Double(double d)
Writes the given double value to the stream.
Definition: writer.h:195
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
bool IsComplete() const
Checks whether the output is a complete JSON.
Definition: writer.h:145
Information for each nested level.
Definition: writer.h:291
string
Definition: rapidjson.h:735
number
Definition: rapidjson.h:736
#define RAPIDJSON_LIKELY(x)
Compiler branching hint for expression with high probability to be true.
Definition: rapidjson.h:494
Writer(OutputStream &os, StackAllocator *stackAllocator=0, size_t levelDepth=kDefaultLevelDepth)
Constructor.
Definition: writer.h:103
Definition: ieee754.h:23
void SetMaxDecimalPlaces(int maxDecimalPlaces)
Sets the maximum number of decimal places for double output.
Definition: writer.h:174
true
Definition: rapidjson.h:732
void Reset(OutputStream &os)
Reset the writer with a new stream.
Definition: writer.h:135
Type
Type of JSON value.
Definition: rapidjson.h:729
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition: rapidjson.h:507
null
Definition: rapidjson.h:730
const Ch * head_
Original head of the string.
Definition: stream.h:169