Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / utils / rapidjson / 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. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed 
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the 
13 // specific language governing permissions and limitations under the License.
14
15 #ifndef RAPIDJSON_WRITER_H_
16 #define RAPIDJSON_WRITER_H_
17
18 #include "stream.h"
19 #include "internal/meta.h"
20 #include "internal/stack.h"
21 #include "internal/strfunc.h"
22 #include "internal/dtoa.h"
23 #include "internal/itoa.h"
24 #include "stringbuffer.h"
25 #include <new>      // placement new
26
27 #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
28 #include <intrin.h>
29 #pragma intrinsic(_BitScanForward)
30 #endif
31 #ifdef RAPIDJSON_SSE42
32 #include <nmmintrin.h>
33 #elif defined(RAPIDJSON_SSE2)
34 #include <emmintrin.h>
35 #elif defined(RAPIDJSON_NEON)
36 #include <arm_neon.h>
37 #endif
38
39 #ifdef __clang__
40 RAPIDJSON_DIAG_PUSH
41 RAPIDJSON_DIAG_OFF(padded)
42 RAPIDJSON_DIAG_OFF(unreachable-code)
43 RAPIDJSON_DIAG_OFF(c++98-compat)
44 #elif defined(_MSC_VER)
45 RAPIDJSON_DIAG_PUSH
46 RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
47 #endif
48
49 RAPIDJSON_NAMESPACE_BEGIN
50
51 ///////////////////////////////////////////////////////////////////////////////
52 // WriteFlag
53
54 /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS 
55     \ingroup RAPIDJSON_CONFIG
56     \brief User-defined kWriteDefaultFlags definition.
57
58     User can define this as any \c WriteFlag combinations.
59 */
60 #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
61 #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
62 #endif
63
64 //! Combination of writeFlags
65 enum WriteFlag {
66     kWriteNoFlags = 0,              //!< No flags are set.
67     kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
68     kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN.
69     kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
70 };
71
72 //! JSON writer
73 /*! Writer implements the concept Handler.
74     It generates JSON text by events to an output os.
75
76     User may programmatically calls the functions of a writer to generate JSON text.
77
78     On the other side, a writer can also be passed to objects that generates events, 
79
80     for example Reader::Parse() and Document::Accept().
81
82     \tparam OutputStream Type of output stream.
83     \tparam SourceEncoding Encoding of source string.
84     \tparam TargetEncoding Encoding of output stream.
85     \tparam StackAllocator Type of allocator for allocating memory of stack.
86     \note implements Handler concept
87 */
88 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
89 class Writer {
90 public:
91     typedef typename SourceEncoding::Ch Ch;
92
93     static const int kDefaultMaxDecimalPlaces = 324;
94
95     //! Constructor
96     /*! \param os Output stream.
97         \param stackAllocator User supplied allocator. If it is null, it will create a private one.
98         \param levelDepth Initial capacity of stack.
99     */
100     explicit
101     Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : 
102         os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
103
104     explicit
105     Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
106         os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
107
108 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
109     Writer(Writer&& rhs) :
110         os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
111         rhs.os_ = 0;
112     }
113 #endif
114
115     //! Reset the writer with a new stream.
116     /*!
117         This function reset the writer with a new stream and default settings,
118         in order to make a Writer object reusable for output multiple JSONs.
119
120         \param os New output stream.
121         \code
122         Writer<OutputStream> writer(os1);
123         writer.StartObject();
124         // ...
125         writer.EndObject();
126
127         writer.Reset(os2);
128         writer.StartObject();
129         // ...
130         writer.EndObject();
131         \endcode
132     */
133     void Reset(OutputStream& os) {
134         os_ = &os;
135         hasRoot_ = false;
136         level_stack_.Clear();
137     }
138
139     //! Checks whether the output is a complete JSON.
140     /*!
141         A complete JSON has a complete root object or array.
142     */
143     bool IsComplete() const {
144         return hasRoot_ && level_stack_.Empty();
145     }
146
147     int GetMaxDecimalPlaces() const {
148         return maxDecimalPlaces_;
149     }
150
151     //! Sets the maximum number of decimal places for double output.
152     /*!
153         This setting truncates the output with specified number of decimal places.
154
155         For example, 
156
157         \code
158         writer.SetMaxDecimalPlaces(3);
159         writer.StartArray();
160         writer.Double(0.12345);                 // "0.123"
161         writer.Double(0.0001);                  // "0.0"
162         writer.Double(1.234567890123456e30);    // "1.234567890123456e30" (do not truncate significand for positive exponent)
163         writer.Double(1.23e-4);                 // "0.0"                  (do truncate significand for negative exponent)
164         writer.EndArray();
165         \endcode
166
167         The default setting does not truncate any decimal places. You can restore to this setting by calling
168         \code
169         writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
170         \endcode
171     */
172     void SetMaxDecimalPlaces(int maxDecimalPlaces) {
173         maxDecimalPlaces_ = maxDecimalPlaces;
174     }
175
176     /*!@name Implementation of Handler
177         \see Handler
178     */
179     //@{
180
181     bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }
182     bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
183     bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); }
184     bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); }
185     bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
186     bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
187
188     //! Writes the given \c double value to the stream
189     /*!
190         \param d The value to be written.
191         \return Whether it is succeed.
192     */
193     bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
194
195     bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
196         RAPIDJSON_ASSERT(str != 0);
197         (void)copy;
198         Prefix(kNumberType);
199         return EndValue(WriteString(str, length));
200     }
201
202     bool String(const Ch* str, SizeType length, bool copy = false) {
203         RAPIDJSON_ASSERT(str != 0);
204         (void)copy;
205         Prefix(kStringType);
206         return EndValue(WriteString(str, length));
207     }
208
209 #if RAPIDJSON_HAS_STDSTRING
210     bool String(const std::basic_string<Ch>& str) {
211         return String(str.data(), SizeType(str.size()));
212     }
213 #endif
214
215     bool StartObject() {
216         Prefix(kObjectType);
217         new (level_stack_.template Push<Level>()) Level(false);
218         return WriteStartObject();
219     }
220
221     bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
222
223 #if RAPIDJSON_HAS_STDSTRING
224     bool Key(const std::basic_string<Ch>& str)
225     {
226       return Key(str.data(), SizeType(str.size()));
227     }
228 #endif
229         
230     bool EndObject(SizeType memberCount = 0) {
231         (void)memberCount;
232         RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
233         RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
234         RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
235         level_stack_.template Pop<Level>(1);
236         return EndValue(WriteEndObject());
237     }
238
239     bool StartArray() {
240         Prefix(kArrayType);
241         new (level_stack_.template Push<Level>()) Level(true);
242         return WriteStartArray();
243     }
244
245     bool EndArray(SizeType elementCount = 0) {
246         (void)elementCount;
247         RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
248         RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
249         level_stack_.template Pop<Level>(1);
250         return EndValue(WriteEndArray());
251     }
252     //@}
253
254     /*! @name Convenience extensions */
255     //@{
256
257     //! Simpler but slower overload.
258     bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
259     bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
260     
261     //@}
262
263     //! Write a raw JSON value.
264     /*!
265         For user to write a stringified JSON as a value.
266
267         \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
268         \param length Length of the json.
269         \param type Type of the root of json.
270     */
271     bool RawValue(const Ch* json, size_t length, Type type) {
272         RAPIDJSON_ASSERT(json != 0);
273         Prefix(type);
274         return EndValue(WriteRawValue(json, length));
275     }
276
277     //! Flush the output stream.
278     /*!
279         Allows the user to flush the output stream immediately.
280      */
281     void Flush() {
282         os_->Flush();
283     }
284
285 protected:
286     //! Information for each nested level
287     struct Level {
288         Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
289         size_t valueCount;  //!< number of values in this level
290         bool inArray;       //!< true if in array, otherwise in object
291     };
292
293     static const size_t kDefaultLevelDepth = 32;
294
295     bool WriteNull()  {
296         PutReserve(*os_, 4);
297         PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
298     }
299
300     bool WriteBool(bool b)  {
301         if (b) {
302             PutReserve(*os_, 4);
303             PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
304         }
305         else {
306             PutReserve(*os_, 5);
307             PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
308         }
309         return true;
310     }
311
312     bool WriteInt(int i) {
313         char buffer[11];
314         const char* end = internal::i32toa(i, buffer);
315         PutReserve(*os_, static_cast<size_t>(end - buffer));
316         for (const char* p = buffer; p != end; ++p)
317             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
318         return true;
319     }
320
321     bool WriteUint(unsigned u) {
322         char buffer[10];
323         const char* end = internal::u32toa(u, buffer);
324         PutReserve(*os_, static_cast<size_t>(end - buffer));
325         for (const char* p = buffer; p != end; ++p)
326             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
327         return true;
328     }
329
330     bool WriteInt64(int64_t i64) {
331         char buffer[21];
332         const char* end = internal::i64toa(i64, buffer);
333         PutReserve(*os_, static_cast<size_t>(end - buffer));
334         for (const char* p = buffer; p != end; ++p)
335             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
336         return true;
337     }
338
339     bool WriteUint64(uint64_t u64) {
340         char buffer[20];
341         char* end = internal::u64toa(u64, buffer);
342         PutReserve(*os_, static_cast<size_t>(end - buffer));
343         for (char* p = buffer; p != end; ++p)
344             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
345         return true;
346     }
347
348     bool WriteDouble(double d) {
349         if (internal::Double(d).IsNanOrInf()) {
350             if (!(writeFlags & kWriteNanAndInfFlag))
351                 return false;
352             if (internal::Double(d).IsNan()) {
353                 PutReserve(*os_, 3);
354                 PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
355                 return true;
356             }
357             if (internal::Double(d).Sign()) {
358                 PutReserve(*os_, 9);
359                 PutUnsafe(*os_, '-');
360             }
361             else
362                 PutReserve(*os_, 8);
363             PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
364             PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
365             return true;
366         }
367
368         char buffer[25];
369         char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
370         PutReserve(*os_, static_cast<size_t>(end - buffer));
371         for (char* p = buffer; p != end; ++p)
372             PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
373         return true;
374     }
375
376     bool WriteString(const Ch* str, SizeType length)  {
377         static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
378         static const char escape[256] = {
379 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
380             //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
381             'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
382             'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
383               0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
384             Z16, Z16,                                                                       // 30~4F
385               0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
386             Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF
387 #undef Z16
388         };
389
390         if (TargetEncoding::supportUnicode)
391             PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
392         else
393             PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..."
394
395         PutUnsafe(*os_, '\"');
396         GenericStringStream<SourceEncoding> is(str);
397         while (ScanWriteUnescapedString(is, length)) {
398             const Ch c = is.Peek();
399             if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
400                 // Unicode escaping
401                 unsigned codepoint;
402                 if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
403                     return false;
404                 PutUnsafe(*os_, '\\');
405                 PutUnsafe(*os_, 'u');
406                 if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
407                     PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
408                     PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]);
409                     PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]);
410                     PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]);
411                 }
412                 else {
413                     RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
414                     // Surrogate pair
415                     unsigned s = codepoint - 0x010000;
416                     unsigned lead = (s >> 10) + 0xD800;
417                     unsigned trail = (s & 0x3FF) + 0xDC00;
418                     PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
419                     PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]);
420                     PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]);
421                     PutUnsafe(*os_, hexDigits[(lead      ) & 15]);
422                     PutUnsafe(*os_, '\\');
423                     PutUnsafe(*os_, 'u');
424                     PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
425                     PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]);
426                     PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]);
427                     PutUnsafe(*os_, hexDigits[(trail      ) & 15]);                    
428                 }
429             }
430             else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  {
431                 is.Take();
432                 PutUnsafe(*os_, '\\');
433                 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
434                 if (escape[static_cast<unsigned char>(c)] == 'u') {
435                     PutUnsafe(*os_, '0');
436                     PutUnsafe(*os_, '0');
437                     PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
438                     PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
439                 }
440             }
441             else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
442                 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
443                 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
444                 return false;
445         }
446         PutUnsafe(*os_, '\"');
447         return true;
448     }
449
450     bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
451         return RAPIDJSON_LIKELY(is.Tell() < length);
452     }
453
454     bool WriteStartObject() { os_->Put('{'); return true; }
455     bool WriteEndObject()   { os_->Put('}'); return true; }
456     bool WriteStartArray()  { os_->Put('['); return true; }
457     bool WriteEndArray()    { os_->Put(']'); return true; }
458
459     bool WriteRawValue(const Ch* json, size_t length) {
460         PutReserve(*os_, length);
461         GenericStringStream<SourceEncoding> is(json);
462         while (RAPIDJSON_LIKELY(is.Tell() < length)) {
463             RAPIDJSON_ASSERT(is.Peek() != '\0');
464             if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
465                 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
466                 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
467                 return false;
468         }
469         return true;
470     }
471
472     void Prefix(Type type) {
473         (void)type;
474         if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
475             Level* level = level_stack_.template Top<Level>();
476             if (level->valueCount > 0) {
477                 if (level->inArray) 
478                     os_->Put(','); // add comma if it is not the first element in array
479                 else  // in object
480                     os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
481             }
482             if (!level->inArray && level->valueCount % 2 == 0)
483                 RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
484             level->valueCount++;
485         }
486         else {
487             RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.
488             hasRoot_ = true;
489         }
490     }
491
492     // Flush the value if it is the top level one.
493     bool EndValue(bool ret) {
494         if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text
495             Flush();
496         return ret;
497     }
498
499     OutputStream* os_;
500     internal::Stack<StackAllocator> level_stack_;
501     int maxDecimalPlaces_;
502     bool hasRoot_;
503
504 private:
505     // Prohibit copy constructor & assignment operator.
506     Writer(const Writer&);
507     Writer& operator=(const Writer&);
508 };
509
510 // Full specialization for StringStream to prevent memory copying
511
512 template<>
513 inline bool Writer<StringBuffer>::WriteInt(int i) {
514     char *buffer = os_->Push(11);
515     const char* end = internal::i32toa(i, buffer);
516     os_->Pop(static_cast<size_t>(11 - (end - buffer)));
517     return true;
518 }
519
520 template<>
521 inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
522     char *buffer = os_->Push(10);
523     const char* end = internal::u32toa(u, buffer);
524     os_->Pop(static_cast<size_t>(10 - (end - buffer)));
525     return true;
526 }
527
528 template<>
529 inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
530     char *buffer = os_->Push(21);
531     const char* end = internal::i64toa(i64, buffer);
532     os_->Pop(static_cast<size_t>(21 - (end - buffer)));
533     return true;
534 }
535
536 template<>
537 inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
538     char *buffer = os_->Push(20);
539     const char* end = internal::u64toa(u, buffer);
540     os_->Pop(static_cast<size_t>(20 - (end - buffer)));
541     return true;
542 }
543
544 template<>
545 inline bool Writer<StringBuffer>::WriteDouble(double d) {
546     if (internal::Double(d).IsNanOrInf()) {
547         // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
548         if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
549             return false;
550         if (internal::Double(d).IsNan()) {
551             PutReserve(*os_, 3);
552             PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
553             return true;
554         }
555         if (internal::Double(d).Sign()) {
556             PutReserve(*os_, 9);
557             PutUnsafe(*os_, '-');
558         }
559         else
560             PutReserve(*os_, 8);
561         PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
562         PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
563         return true;
564     }
565     
566     char *buffer = os_->Push(25);
567     char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
568     os_->Pop(static_cast<size_t>(25 - (end - buffer)));
569     return true;
570 }
571
572 #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
573 template<>
574 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
575     if (length < 16)
576         return RAPIDJSON_LIKELY(is.Tell() < length);
577
578     if (!RAPIDJSON_LIKELY(is.Tell() < length))
579         return false;
580
581     const char* p = is.src_;
582     const char* end = is.head_ + length;
583     const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
584     const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
585     if (nextAligned > end)
586         return true;
587
588     while (p != nextAligned)
589         if (*p < 0x20 || *p == '\"' || *p == '\\') {
590             is.src_ = p;
591             return RAPIDJSON_LIKELY(is.Tell() < length);
592         }
593         else
594             os_->PutUnsafe(*p++);
595
596     // The rest of string using SIMD
597     static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
598     static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
599     static const char space[16]  = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
600     const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
601     const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
602     const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
603
604     for (; p != endAligned; p += 16) {
605         const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
606         const __m128i t1 = _mm_cmpeq_epi8(s, dq);
607         const __m128i t2 = _mm_cmpeq_epi8(s, bs);
608         const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
609         const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
610         unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
611         if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped
612             SizeType len;
613 #ifdef _MSC_VER         // Find the index of first escaped
614             unsigned long offset;
615             _BitScanForward(&offset, r);
616             len = offset;
617 #else
618             len = static_cast<SizeType>(__builtin_ffs(r) - 1);
619 #endif
620             char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
621             for (size_t i = 0; i < len; i++)
622                 q[i] = p[i];
623
624             p += len;
625             break;
626         }
627         _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
628     }
629
630     is.src_ = p;
631     return RAPIDJSON_LIKELY(is.Tell() < length);
632 }
633 #elif defined(RAPIDJSON_NEON)
634 template<>
635 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
636     if (length < 16)
637         return RAPIDJSON_LIKELY(is.Tell() < length);
638
639     if (!RAPIDJSON_LIKELY(is.Tell() < length))
640         return false;
641
642     const char* p = is.src_;
643     const char* end = is.head_ + length;
644     const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
645     const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
646     if (nextAligned > end)
647         return true;
648
649     while (p != nextAligned)
650         if (*p < 0x20 || *p == '\"' || *p == '\\') {
651             is.src_ = p;
652             return RAPIDJSON_LIKELY(is.Tell() < length);
653         }
654         else
655             os_->PutUnsafe(*p++);
656
657     // The rest of string using SIMD
658     const uint8x16_t s0 = vmovq_n_u8('"');
659     const uint8x16_t s1 = vmovq_n_u8('\\');
660     const uint8x16_t s2 = vmovq_n_u8('\b');
661     const uint8x16_t s3 = vmovq_n_u8(32);
662
663     for (; p != endAligned; p += 16) {
664         const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
665         uint8x16_t x = vceqq_u8(s, s0);
666         x = vorrq_u8(x, vceqq_u8(s, s1));
667         x = vorrq_u8(x, vceqq_u8(s, s2));
668         x = vorrq_u8(x, vcltq_u8(s, s3));
669
670         x = vrev64q_u8(x);                     // Rev in 64
671         uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0);   // extract
672         uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1);  // extract
673
674         SizeType len = 0;
675         bool escaped = false;
676         if (low == 0) {
677             if (high != 0) {
678                 unsigned lz = (unsigned)__builtin_clzll(high);
679                 len = 8 + (lz >> 3);
680                 escaped = true;
681             }
682         } else {
683             unsigned lz = (unsigned)__builtin_clzll(low);
684             len = lz >> 3;
685             escaped = true;
686         }
687         if (RAPIDJSON_UNLIKELY(escaped)) {   // some of characters is escaped
688             char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
689             for (size_t i = 0; i < len; i++)
690                 q[i] = p[i];
691
692             p += len;
693             break;
694         }
695         vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
696     }
697
698     is.src_ = p;
699     return RAPIDJSON_LIKELY(is.Tell() < length);
700 }
701 #endif // RAPIDJSON_NEON
702
703 RAPIDJSON_NAMESPACE_END
704
705 #if defined(_MSC_VER) || defined(__clang__)
706 RAPIDJSON_DIAG_POP
707 #endif
708
709 #endif // RAPIDJSON_RAPIDJSON_H_