Coverage Report

Created: 2026-06-07 06:59

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