Coverage Report

Created: 2026-10-28 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/contrib/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
7.27k
        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
2.04k
    bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }
184
2.16k
    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
185
1.42M
    bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); }
186
0
    bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); }
187
0
    bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
188
0
    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
752k
    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
3.16M
    bool String(const Ch* str, SizeType length, bool copy = false) {
205
3.16M
        RAPIDJSON_ASSERT(str != 0);
206
3.16M
        (void)copy;
207
3.16M
        Prefix(kStringType);
208
3.16M
        return EndValue(WriteString(str, length));
209
3.16M
    }
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
661k
    bool StartObject() {
218
661k
        Prefix(kObjectType);
219
661k
        new (level_stack_.template Push<Level>()) Level(false);
220
661k
        return WriteStartObject();
221
661k
    }
222
223
2.50M
    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
661k
    bool EndObject(SizeType memberCount = 0) {
233
661k
        (void)memberCount;
234
661k
        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
235
661k
        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
236
661k
        RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
237
661k
        level_stack_.template Pop<Level>(1);
238
661k
        return EndValue(WriteEndObject());
239
661k
    }
240
241
382k
    bool StartArray() {
242
382k
        Prefix(kArrayType);
243
382k
        new (level_stack_.template Push<Level>()) Level(true);
244
382k
        return WriteStartArray();
245
382k
    }
246
247
382k
    bool EndArray(SizeType elementCount = 0) {
248
382k
        (void)elementCount;
249
382k
        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
250
382k
        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
251
382k
        level_stack_.template Pop<Level>(1);
252
382k
        return EndValue(WriteEndArray());
253
382k
    }
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
10.8k
    void Flush() {
284
10.8k
        os_->Flush();
285
10.8k
    }
286
287
    static const size_t kDefaultLevelDepth = 32;
288
289
protected:
290
    //! Information for each nested level
291
    struct Level {
292
2.08M
        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
4.08k
    bool WriteNull()  {
298
4.08k
        PutReserve(*os_, 4);
299
4.08k
        PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
300
4.08k
    }
301
302
4.33k
    bool WriteBool(bool b)  {
303
4.33k
        if (b) {
304
1.85k
            PutReserve(*os_, 4);
305
1.85k
            PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
306
1.85k
        }
307
2.48k
        else {
308
2.48k
            PutReserve(*os_, 5);
309
2.48k
            PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
310
2.48k
        }
311
4.33k
        return true;
312
4.33k
    }
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
6.33M
    bool WriteString(const Ch* str, SizeType length)  {
384
6.33M
        static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
385
6.33M
        static const char escape[256] = {
386
76.0M
#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
6.33M
            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
389
6.33M
            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
390
6.33M
              0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
391
6.33M
            Z16, Z16,                                                                       // 30~4F
392
6.33M
              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
393
6.33M
            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF
394
6.33M
#undef Z16
395
6.33M
        };
396
397
6.33M
        if (TargetEncoding::supportUnicode)
398
6.33M
            PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
399
0
        else
400
0
            PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..."
401
402
6.33M
        PutUnsafe(*os_, '\"');
403
6.33M
        GenericStringStream<SourceEncoding> is(str);
404
77.3M
        while (ScanWriteUnescapedString(is, length)) {
405
71.0M
            const Ch c = is.Peek();
406
71.0M
            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
71.0M
            else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  {
438
501k
                is.Take();
439
501k
                PutUnsafe(*os_, '\\');
440
501k
                PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
441
501k
                if (escape[static_cast<unsigned char>(c)] == 'u') {
442
202k
                    PutUnsafe(*os_, '0');
443
202k
                    PutUnsafe(*os_, '0');
444
202k
                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
445
202k
                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
446
202k
                }
447
501k
            }
448
70.4M
            else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
449
70.4M
                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
450
70.4M
                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
451
0
                return false;
452
71.0M
        }
453
6.33M
        PutUnsafe(*os_, '\"');
454
6.33M
        return true;
455
6.33M
    }
456
457
77.3M
    bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
458
77.3M
        return RAPIDJSON_LIKELY(is.Tell() < length);
459
77.3M
    }
460
461
1.32M
    bool WriteStartObject() { os_->Put('{'); return true; }
462
1.32M
    bool WriteEndObject()   { os_->Put('}'); return true; }
463
764k
    bool WriteStartArray()  { os_->Put('['); return true; }
464
764k
    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
6.39M
    void Prefix(Type type) {
480
6.39M
        (void)type;
481
6.39M
        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
482
6.38M
            Level* level = level_stack_.template Top<Level>();
483
6.38M
            if (level->valueCount > 0) {
484
5.42M
                if (level->inArray) 
485
995k
                    os_->Put(','); // add comma if it is not the first element in array
486
4.43M
                else  // in object
487
4.43M
                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
488
5.42M
            }
489
6.38M
            if (!level->inArray && level->valueCount % 2 == 0)
490
6.38M
                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
491
6.38M
            level->valueCount++;
492
6.38M
        }
493
3.63k
        else {
494
3.63k
            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.
495
3.63k
            hasRoot_ = true;
496
3.63k
        }
497
6.39M
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Prefix(rapidjson::Type)
rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Prefix(rapidjson::Type)
Line
Count
Source
479
6.39M
    void Prefix(Type type) {
480
6.39M
        (void)type;
481
6.39M
        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
482
6.38M
            Level* level = level_stack_.template Top<Level>();
483
6.38M
            if (level->valueCount > 0) {
484
5.42M
                if (level->inArray) 
485
995k
                    os_->Put(','); // add comma if it is not the first element in array
486
4.43M
                else  // in object
487
4.43M
                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
488
5.42M
            }
489
6.38M
            if (!level->inArray && level->valueCount % 2 == 0)
490
6.38M
                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
491
6.38M
            level->valueCount++;
492
6.38M
        }
493
3.63k
        else {
494
3.63k
            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.
495
3.63k
            hasRoot_ = true;
496
3.63k
        }
497
6.39M
    }
498
499
    // Flush the value if it is the top level one.
500
12.8M
    bool EndValue(bool ret) {
501
12.8M
        if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text
502
7.22k
            Flush();
503
12.8M
        return ret;
504
12.8M
    }
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
2.86M
inline bool Writer<StringBuffer>::WriteInt(int i) {
521
2.86M
    char *buffer = os_->Push(11);
522
2.86M
    const char* end = internal::i32toa(i, buffer);
523
2.86M
    os_->Pop(static_cast<size_t>(11 - (end - buffer)));
524
2.86M
    return true;
525
2.86M
}
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
0
inline bool Writer<StringBuffer>::WriteDouble(double d) {
553
0
    if (internal::Double(d).IsNanOrInf()) {
554
0
        // 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
0
    
578
0
    char *buffer = os_->Push(25);
579
0
    char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
580
0
    os_->Pop(static_cast<size_t>(25 - (end - buffer)));
581
0
    return true;
582
0
}
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_