Arcane  v3.16.8.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
writer.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2// Tencent is pleased to support the open source community by making RapidJSON available.
3//
4// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
5//
6// Licensed under the MIT License (the "License"); you may not use this file except
7// in compliance with the License. You may obtain a copy of the License at
8//
9// http://opensource.org/licenses/MIT
10//
11// Unless required by applicable law or agreed to in writing, software distributed
12// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
13// CONDITIONS OF ANY KIND, either express or implied. See the License for the
14// specific language governing permissions and limitations under the License.
15
16#ifndef RAPIDJSON_WRITER_H_
17#define RAPIDJSON_WRITER_H_
18
19#include "stream.h"
20#include "internal/clzll.h"
21#include "internal/meta.h"
22#include "internal/stack.h"
23#include "internal/strfunc.h"
24#include "internal/dtoa.h"
25#include "internal/itoa.h"
26#include "stringbuffer.h"
27#include <new> // placement new
28
29#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
30#include <intrin.h>
31#pragma intrinsic(_BitScanForward)
32#endif
33#ifdef RAPIDJSON_SSE42
34#include <nmmintrin.h>
35#elif defined(RAPIDJSON_SSE2)
36#include <emmintrin.h>
37#elif defined(RAPIDJSON_NEON)
38#include <arm_neon.h>
39#endif
40
41#ifdef __clang__
42RAPIDJSON_DIAG_PUSH
43RAPIDJSON_DIAG_OFF(padded)
44RAPIDJSON_DIAG_OFF(unreachable-code)
45RAPIDJSON_DIAG_OFF(c++98-compat)
46#elif defined(_MSC_VER)
47RAPIDJSON_DIAG_PUSH
48RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
49#endif
50
52
54// WriteFlag
55
62#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
63#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
64#endif
65
67enum WriteFlag {
68 kWriteNoFlags = 0,
69 kWriteValidateEncodingFlag = 1,
70 kWriteNanAndInfFlag = 2,
71 kWriteNanAndInfNullFlag = 4,
72 kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS
73};
74
76
91template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
92class Writer {
93public:
94 typedef typename SourceEncoding::Ch Ch;
95
96 static const int kDefaultMaxDecimalPlaces = 324;
97
99
103 explicit
104 Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
105 os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
106
107 explicit
108 Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
109 os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
110
111#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
112 Writer(Writer&& rhs) :
113 os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
114 rhs.os_ = 0;
115 }
116#endif
117
119
136 void Reset(OutputStream& os) {
137 os_ = &os;
138 hasRoot_ = false;
139 level_stack_.Clear();
140 }
141
143
146 bool IsComplete() const {
147 return hasRoot_ && level_stack_.Empty();
148 }
149
150 int GetMaxDecimalPlaces() const {
151 return maxDecimalPlaces_;
152 }
153
155
175 void SetMaxDecimalPlaces(int maxDecimalPlaces) {
176 maxDecimalPlaces_ = maxDecimalPlaces;
177 }
178
183
184 bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
185 bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
186 bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
187 bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
188 bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
189 bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
190
192
196 bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
197
198 bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
199 RAPIDJSON_ASSERT(str != 0);
200 (void)copy;
201 Prefix(kNumberType);
202 return EndValue(WriteString(str, length));
203 }
204
205 bool String(const Ch* str, SizeType length, bool copy = false) {
206 RAPIDJSON_ASSERT(str != 0);
207 (void)copy;
208 Prefix(kStringType);
209 return EndValue(WriteString(str, length));
210 }
211
212#if RAPIDJSON_HAS_STDSTRING
213 bool String(const std::basic_string<Ch>& str) {
214 return String(str.data(), SizeType(str.size()));
215 }
216#endif
217
218 bool StartObject() {
219 Prefix(kObjectType);
220 new (level_stack_.template Push<Level>()) Level(false);
221 return WriteStartObject();
222 }
223
224 bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
225
226#if RAPIDJSON_HAS_STDSTRING
227 bool Key(const std::basic_string<Ch>& str)
228 {
229 return Key(str.data(), SizeType(str.size()));
230 }
231#endif
232
233 bool EndObject(SizeType memberCount = 0) {
234 (void)memberCount;
235 RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
236 RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
237 RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
238 level_stack_.template Pop<Level>(1);
239 return EndValue(WriteEndObject());
240 }
241
242 bool StartArray() {
243 Prefix(kArrayType);
244 new (level_stack_.template Push<Level>()) Level(true);
245 return WriteStartArray();
246 }
247
248 bool EndArray(SizeType elementCount = 0) {
249 (void)elementCount;
250 RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
251 RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
252 level_stack_.template Pop<Level>(1);
253 return EndValue(WriteEndArray());
254 }
256
259
261 bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
262 bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
263
265
267
274 bool RawValue(const Ch* json, size_t length, Type type) {
275 RAPIDJSON_ASSERT(json != 0);
276 Prefix(type);
277 return EndValue(WriteRawValue(json, length));
278 }
279
281
284 void Flush() {
285 os_->Flush();
286 }
287
288 static const size_t kDefaultLevelDepth = 32;
289
290protected:
292 struct Level {
293 Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
294 size_t valueCount;
295 bool inArray;
296 };
297
298 bool WriteNull() {
299 PutReserve(*os_, 4);
300 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
301 }
302
303 bool WriteBool(bool b) {
304 if (b) {
305 PutReserve(*os_, 4);
306 PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
307 }
308 else {
309 PutReserve(*os_, 5);
310 PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
311 }
312 return true;
313 }
314
315 bool WriteInt(int i) {
316 char buffer[11];
317 const char* end = internal::i32toa(i, buffer);
318 PutReserve(*os_, static_cast<size_t>(end - buffer));
319 for (const char* p = buffer; p != end; ++p)
320 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
321 return true;
322 }
323
324 bool WriteUint(unsigned u) {
325 char buffer[10];
326 const char* end = internal::u32toa(u, buffer);
327 PutReserve(*os_, static_cast<size_t>(end - buffer));
328 for (const char* p = buffer; p != end; ++p)
329 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
330 return true;
331 }
332
333 bool WriteInt64(int64_t i64) {
334 char buffer[21];
335 const char* end = internal::i64toa(i64, buffer);
336 PutReserve(*os_, static_cast<size_t>(end - buffer));
337 for (const char* p = buffer; p != end; ++p)
338 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
339 return true;
340 }
341
342 bool WriteUint64(uint64_t u64) {
343 char buffer[20];
344 char* end = internal::u64toa(u64, buffer);
345 PutReserve(*os_, static_cast<size_t>(end - buffer));
346 for (char* p = buffer; p != end; ++p)
347 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
348 return true;
349 }
350
351 bool WriteDouble(double d) {
352 if (internal::Double(d).IsNanOrInf()) {
353 if (!(writeFlags & kWriteNanAndInfFlag) && !(writeFlags & kWriteNanAndInfNullFlag))
354 return false;
355 if (writeFlags & kWriteNanAndInfNullFlag) {
356 PutReserve(*os_, 4);
357 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
358 return true;
359 }
360 if (internal::Double(d).IsNan()) {
361 PutReserve(*os_, 3);
362 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
363 return true;
364 }
365 if (internal::Double(d).Sign()) {
366 PutReserve(*os_, 9);
367 PutUnsafe(*os_, '-');
368 }
369 else
370 PutReserve(*os_, 8);
371 PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
372 PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
373 return true;
374 }
375
376 char buffer[25];
377 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
378 PutReserve(*os_, static_cast<size_t>(end - buffer));
379 for (char* p = buffer; p != end; ++p)
380 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
381 return true;
382 }
383
384 bool WriteString(const Ch* str, SizeType length) {
385 static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
386 static const char escape[256] = {
387#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
388 //0 1 2 3 4 5 6 7 8 9 A B C D E F
389 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
390 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
391 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
392 Z16, Z16, // 30~4F
393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
394 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
395#undef Z16
396 };
397
398 if (TargetEncoding::supportUnicode)
399 PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
400 else
401 PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
402
403 PutUnsafe(*os_, '\"');
404 GenericStringStream<SourceEncoding> is(str);
405 while (ScanWriteUnescapedString(is, length)) {
406 const Ch c = is.Peek();
407 if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
408 // Unicode escaping
409 unsigned codepoint;
410 if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
411 return false;
412 PutUnsafe(*os_, '\\');
413 PutUnsafe(*os_, 'u');
414 if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
415 PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
416 PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
417 PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
418 PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
419 }
420 else {
421 RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
422 // Surrogate pair
423 unsigned s = codepoint - 0x010000;
424 unsigned lead = (s >> 10) + 0xD800;
425 unsigned trail = (s & 0x3FF) + 0xDC00;
426 PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
427 PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
428 PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
429 PutUnsafe(*os_, hexDigits[(lead ) & 15]);
430 PutUnsafe(*os_, '\\');
431 PutUnsafe(*os_, 'u');
432 PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
433 PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
434 PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
435 PutUnsafe(*os_, hexDigits[(trail ) & 15]);
436 }
437 }
438 else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
439 is.Take();
440 PutUnsafe(*os_, '\\');
441 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
442 if (escape[static_cast<unsigned char>(c)] == 'u') {
443 PutUnsafe(*os_, '0');
444 PutUnsafe(*os_, '0');
445 PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
446 PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
447 }
448 }
449 else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
451 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
452 return false;
453 }
454 PutUnsafe(*os_, '\"');
455 return true;
456 }
457
458 bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
459 return RAPIDJSON_LIKELY(is.Tell() < length);
460 }
461
462 bool WriteStartObject() { os_->Put('{'); return true; }
463 bool WriteEndObject() { os_->Put('}'); return true; }
464 bool WriteStartArray() { os_->Put('['); return true; }
465 bool WriteEndArray() { os_->Put(']'); return true; }
466
467 bool WriteRawValue(const Ch* json, size_t length) {
468 PutReserve(*os_, length);
469 GenericStringStream<SourceEncoding> is(json);
470 while (RAPIDJSON_LIKELY(is.Tell() < length)) {
471 RAPIDJSON_ASSERT(is.Peek() != '\0');
472 if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
474 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
475 return false;
476 }
477 return true;
478 }
479
480 void Prefix(Type type) {
481 (void)type;
482 if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
483 Level* level = level_stack_.template Top<Level>();
484 if (level->valueCount > 0) {
485 if (level->inArray)
486 os_->Put(','); // add comma if it is not the first element in array
487 else // in object
488 os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
489 }
490 if (!level->inArray && level->valueCount % 2 == 0)
491 RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
492 level->valueCount++;
493 }
494 else {
495 RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
496 hasRoot_ = true;
497 }
498 }
499
500 // Flush the value if it is the top level one.
501 bool EndValue(bool ret) {
502 if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
503 Flush();
504 return ret;
505 }
506
507 OutputStream* os_;
508 internal::Stack<StackAllocator> level_stack_;
509 int maxDecimalPlaces_;
510 bool hasRoot_;
511
512private:
513 // Prohibit copy constructor & assignment operator.
514 Writer(const Writer&);
515 Writer& operator=(const Writer&);
516};
517
518// Full specialization for StringStream to prevent memory copying
519
520template<>
521inline bool Writer<StringBuffer>::WriteInt(int i) {
522 char *buffer = os_->Push(11);
523 const char* end = internal::i32toa(i, buffer);
524 os_->Pop(static_cast<size_t>(11 - (end - buffer)));
525 return true;
526}
527
528template<>
529inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
530 char *buffer = os_->Push(10);
531 const char* end = internal::u32toa(u, buffer);
532 os_->Pop(static_cast<size_t>(10 - (end - buffer)));
533 return true;
534}
535
536template<>
537inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
538 char *buffer = os_->Push(21);
539 const char* end = internal::i64toa(i64, buffer);
540 os_->Pop(static_cast<size_t>(21 - (end - buffer)));
541 return true;
542}
543
544template<>
545inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
546 char *buffer = os_->Push(20);
547 const char* end = internal::u64toa(u, buffer);
548 os_->Pop(static_cast<size_t>(20 - (end - buffer)));
549 return true;
550}
551
552template<>
553inline bool Writer<StringBuffer>::WriteDouble(double d) {
554 if (internal::Double(d).IsNanOrInf()) {
555 // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
556 if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
557 return false;
558 if (kWriteDefaultFlags & kWriteNanAndInfNullFlag) {
559 PutReserve(*os_, 4);
560 PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l');
561 return true;
562 }
563 if (internal::Double(d).IsNan()) {
564 PutReserve(*os_, 3);
565 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
566 return true;
567 }
568 if (internal::Double(d).Sign()) {
569 PutReserve(*os_, 9);
570 PutUnsafe(*os_, '-');
571 }
572 else
573 PutReserve(*os_, 8);
574 PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
575 PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
576 return true;
577 }
578
579 char *buffer = os_->Push(25);
580 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
581 os_->Pop(static_cast<size_t>(25 - (end - buffer)));
582 return true;
583}
584
585#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
586template<>
587inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
588 if (length < 16)
589 return RAPIDJSON_LIKELY(is.Tell() < length);
590
591 if (!RAPIDJSON_LIKELY(is.Tell() < length))
592 return false;
593
594 const char* p = is.src_;
595 const char* end = is.head_ + length;
596 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
597 const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
598 if (nextAligned > end)
599 return true;
600
601 while (p != nextAligned)
602 if (*p < 0x20 || *p == '\"' || *p == '\\') {
603 is.src_ = p;
604 return RAPIDJSON_LIKELY(is.Tell() < length);
605 }
606 else
607 os_->PutUnsafe(*p++);
608
609 // The rest of string using SIMD
610 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
611 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
612 static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
613 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
614 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
615 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
616
617 for (; p != endAligned; p += 16) {
618 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
619 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
620 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
621 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
622 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
623 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
624 if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
626#ifdef _MSC_VER // Find the index of first escaped
627 unsigned long offset;
628 _BitScanForward(&offset, r);
629 len = offset;
630#else
631 len = static_cast<SizeType>(__builtin_ffs(r) - 1);
632#endif
633 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
634 for (size_t i = 0; i < len; i++)
635 q[i] = p[i];
636
637 p += len;
638 break;
639 }
640 _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
641 }
642
643 is.src_ = p;
644 return RAPIDJSON_LIKELY(is.Tell() < length);
645}
646#elif defined(RAPIDJSON_NEON)
647template<>
648inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
649 if (length < 16)
650 return RAPIDJSON_LIKELY(is.Tell() < length);
651
652 if (!RAPIDJSON_LIKELY(is.Tell() < length))
653 return false;
654
655 const char* p = is.src_;
656 const char* end = is.head_ + length;
657 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
658 const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
659 if (nextAligned > end)
660 return true;
661
662 while (p != nextAligned)
663 if (*p < 0x20 || *p == '\"' || *p == '\\') {
664 is.src_ = p;
665 return RAPIDJSON_LIKELY(is.Tell() < length);
666 }
667 else
668 os_->PutUnsafe(*p++);
669
670 // The rest of string using SIMD
671 const uint8x16_t s0 = vmovq_n_u8('"');
672 const uint8x16_t s1 = vmovq_n_u8('\\');
673 const uint8x16_t s2 = vmovq_n_u8('\b');
674 const uint8x16_t s3 = vmovq_n_u8(32);
675
676 for (; p != endAligned; p += 16) {
677 const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
678 uint8x16_t x = vceqq_u8(s, s0);
679 x = vorrq_u8(x, vceqq_u8(s, s1));
680 x = vorrq_u8(x, vceqq_u8(s, s2));
681 x = vorrq_u8(x, vcltq_u8(s, s3));
682
683 x = vrev64q_u8(x); // Rev in 64
684 uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
685 uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
686
687 SizeType len = 0;
688 bool escaped = false;
689 if (low == 0) {
690 if (high != 0) {
691 uint32_t lz = internal::clzll(high);
692 len = 8 + (lz >> 3);
693 escaped = true;
694 }
695 } else {
696 uint32_t lz = internal::clzll(low);
697 len = lz >> 3;
698 escaped = true;
699 }
700 if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
701 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
702 for (size_t i = 0; i < len; i++)
703 q[i] = p[i];
704
705 p += len;
706 break;
707 }
708 vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
709 }
710
711 is.src_ = p;
712 return RAPIDJSON_LIKELY(is.Tell() < length);
713}
714#endif // RAPIDJSON_NEON
715
717
718#if defined(_MSC_VER) || defined(__clang__)
719RAPIDJSON_DIAG_POP
720#endif
721
722#endif // RAPIDJSON_RAPIDJSON_H_
bool IsComplete() const
Checks whether the output is a complete JSON.
Definition writer.h:146
bool Double(double d)
Writes the given double value to the stream.
Definition writer.h:196
bool String(const Ch *const &str)
Simpler but slower overload.
Definition writer.h:261
void SetMaxDecimalPlaces(int maxDecimalPlaces)
Sets the maximum number of decimal places for double output.
Definition writer.h:175
void Reset(OutputStream &os)
Reset the writer with a new stream.
Definition writer.h:136
void Flush()
Flush the output stream.
Definition writer.h:284
bool RawValue(const Ch *json, size_t length, Type type)
Write a raw JSON value.
Definition writer.h:274
Writer(OutputStream &os, StackAllocator *stackAllocator=0, size_t levelDepth=kDefaultLevelDepth)
Constructor.
Definition writer.h:104
#define RAPIDJSON_LIKELY(x)
Compiler branching hint for expression with high probability to be true.
Definition rapidjson.h:495
#define RAPIDJSON_UNLIKELY(x)
Compiler branching hint for expression with low probability to be true.
Definition rapidjson.h:508
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:438
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:122
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:125
Integer len(const char *s)
Retourne la longueur de la chaîne s.
Type
Type of JSON value.
Definition rapidjson.h:730
@ kFalseType
false
Definition rapidjson.h:732
@ kObjectType
object
Definition rapidjson.h:734
@ kTrueType
true
Definition rapidjson.h:733
@ kStringType
string
Definition rapidjson.h:736
@ kNullType
null
Definition rapidjson.h:731
@ kArrayType
array
Definition rapidjson.h:735
@ kNumberType
number
Definition rapidjson.h:737
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition rapidjson.h:416
const Ch * head_
Original head of the string.
Definition stream.h:170
const Ch * src_
Current read position.
Definition stream.h:169
static RAPIDJSON_FORCEINLINE bool Validate(InputStream &is, OutputStream &os)
Validate one Unicode codepoint from an encoded stream.
Definition encodings.h:681
Information for each nested level.
Definition writer.h:292
size_t valueCount
number of values in this level
Definition writer.h:294
bool inArray
true if in array, otherwise in object
Definition writer.h:295