Coverage Report

Created: 2026-01-25 07:15

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
0
        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
0
    bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }
184
0
    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
185
0
    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
0
    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
0
    bool String(const Ch* str, SizeType length, bool copy = false) {
205
0
        RAPIDJSON_ASSERT(str != 0);
206
0
        (void)copy;
207
0
        Prefix(kStringType);
208
0
        return EndValue(WriteString(str, length));
209
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::String(char const*, unsigned int, bool)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::String(char const*, unsigned int, bool)
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
0
    bool StartObject() {
218
0
        Prefix(kObjectType);
219
0
        new (level_stack_.template Push<Level>()) Level(false);
220
0
        return WriteStartObject();
221
0
    }
222
223
0
    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
0
    bool EndObject(SizeType memberCount = 0) {
233
0
        (void)memberCount;
234
0
        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
235
0
        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
236
0
        RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
237
0
        level_stack_.template Pop<Level>(1);
238
0
        return EndValue(WriteEndObject());
239
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::EndObject(unsigned int)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::EndObject(unsigned int)
240
241
0
    bool StartArray() {
242
0
        Prefix(kArrayType);
243
0
        new (level_stack_.template Push<Level>()) Level(true);
244
0
        return WriteStartArray();
245
0
    }
246
247
0
    bool EndArray(SizeType elementCount = 0) {
248
0
        (void)elementCount;
249
0
        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
250
0
        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
251
0
        level_stack_.template Pop<Level>(1);
252
0
        return EndValue(WriteEndArray());
253
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::EndArray(unsigned int)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::EndArray(unsigned int)
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
0
    void Flush() {
284
0
        os_->Flush();
285
0
    }
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
0
    bool WriteString(const Ch* str, SizeType length)  {
384
0
        static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
385
0
        static const char escape[256] = {
386
0
#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
0
            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
389
0
            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
390
0
              0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
391
0
            Z16, Z16,                                                                       // 30~4F
392
0
              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
393
0
            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF
394
0
#undef Z16
395
0
        };
396
397
0
        if (TargetEncoding::supportUnicode)
398
0
            PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
399
0
        else
400
0
            PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..."
401
402
0
        PutUnsafe(*os_, '\"');
403
0
        GenericStringStream<SourceEncoding> is(str);
404
0
        while (ScanWriteUnescapedString(is, length)) {
405
0
            const Ch c = is.Peek();
406
0
            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
0
            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
0
            else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
449
0
                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
450
0
                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
451
0
                return false;
452
0
        }
453
0
        PutUnsafe(*os_, '\"');
454
0
        return true;
455
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::WriteString(char const*, unsigned int)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::WriteString(char const*, unsigned int)
456
457
0
    bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
458
0
        return RAPIDJSON_LIKELY(is.Tell() < length);
459
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::ScanWriteUnescapedString(rapidjson::GenericStringStream<rapidjson::UTF8<char> >&, unsigned long)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::ScanWriteUnescapedString(rapidjson::GenericStringStream<rapidjson::UTF8<char> >&, unsigned long)
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
0
    void Prefix(Type type) {
480
0
        (void)type;
481
0
        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
482
0
            Level* level = level_stack_.template Top<Level>();
483
0
            if (level->valueCount > 0) {
484
0
                if (level->inArray) 
485
0
                    os_->Put(','); // add comma if it is not the first element in array
486
0
                else  // in object
487
0
                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
488
0
            }
489
0
            if (!level->inArray && level->valueCount % 2 == 0)
490
0
                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
491
0
            level->valueCount++;
492
0
        }
493
0
        else {
494
0
            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.
495
0
            hasRoot_ = true;
496
0
        }
497
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Prefix(rapidjson::Type)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::Prefix(rapidjson::Type)
498
499
    // Flush the value if it is the top level one.
500
0
    bool EndValue(bool ret) {
501
0
        if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text
502
0
            Flush();
503
0
        return ret;
504
0
    }
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::EndValue(bool)
Unexecuted instantiation: rapidjson::Writer<rapidjson::GenericStringBuffer<rapidjson::UTF8<char>, rapidjson::CrtAllocator>, rapidjson::UTF8<char>, rapidjson::UTF8<char>, rapidjson::CrtAllocator, 0u>::EndValue(bool)
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
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_