writer.h

Engine/source/persistence/rapidjson/writer.h

More...

Classes:

class

JSON writer.

class

Information for each nested level.

Public Defines

define
Z16() 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Public Enumerations

enum
WriteFlag {
  kWriteNoFlags = 0
  kWriteValidateEncodingFlag = 1
  kWriteNanAndInfFlag = 2
  kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS
}

Combination of writeFlags.

Detailed Description

Public Defines

RAPIDJSON_WRITE_DEFAULT_FLAGS() 
Z16() 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Public Enumerations

WriteFlag

Enumerator

kWriteNoFlags = 0

No flags are set.

kWriteValidateEncodingFlag = 1

Validate encoding of JSON strings.

kWriteNanAndInfFlag = 2

Allow writing of Infinity, -Infinity and NaN.

kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS

Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS.

Combination of writeFlags.

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