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