Coverage Report

Created: 2025-12-08 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons/json_encoder.hpp
Line
Count
Source
1
// Copyright 2013-2025 Daniel Parker
2
// Distributed under the Boost license, Version 1.0.
3
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5
// See https://github.com/danielaparker/jsoncons for latest version
6
7
#ifndef JSONCONS_JSON_ENCODER_HPP
8
#define JSONCONS_JSON_ENCODER_HPP
9
10
#include <array> // std::array
11
#include <cstddef>
12
#include <cstdint>
13
#include <cmath> // std::isfinite, std::isnan
14
#include <limits> // std::numeric_limits
15
#include <memory>
16
#include <string>
17
#include <utility> // std::move
18
#include <vector>
19
20
#include <jsoncons/config/compiler_support.hpp>
21
#include <jsoncons/config/jsoncons_config.hpp>
22
#include <jsoncons/utility/write_number.hpp>
23
#include <jsoncons/json_error.hpp>
24
#include <jsoncons/json_exception.hpp>
25
#include <jsoncons/json_options.hpp>
26
#include <jsoncons/json_type.hpp>
27
#include <jsoncons/json_visitor.hpp>
28
#include <jsoncons/semantic_tag.hpp>
29
#include <jsoncons/ser_util.hpp>
30
#include <jsoncons/sink.hpp>
31
#include <jsoncons/utility/bigint.hpp>
32
#include <jsoncons/utility/byte_string.hpp>
33
#include <jsoncons/utility/unicode_traits.hpp>
34
35
namespace jsoncons { 
36
namespace detail {
37
38
    inline
39
    bool is_control_character(uint32_t c)
40
3.65M
    {
41
3.65M
        return c <= 0x1F || c == 0x7f;
42
3.65M
    }
43
44
    inline
45
    bool is_non_ascii_codepoint(uint32_t cp)
46
172k
    {
47
172k
        return cp >= 0x80;
48
172k
    }
49
50
    template <typename CharT,typename Sink>
51
    std::size_t escape_string(const CharT* s, std::size_t length,
52
                         bool escape_all_non_ascii, bool escape_solidus,
53
                         Sink& sink)
54
273k
    {
55
273k
        std::size_t count = 0;
56
273k
        const CharT* begin = s;
57
273k
        const CharT* end = s + length;
58
3.75M
        for (const CharT* it = begin; it != end; ++it)
59
3.48M
        {
60
3.48M
            CharT c = *it;
61
3.48M
            switch (c)
62
3.48M
            {
63
4.36k
                case '\\':
64
4.36k
                    sink.push_back('\\');
65
4.36k
                    sink.push_back('\\');
66
4.36k
                    count += 2;
67
4.36k
                    break;
68
378
                case '"':
69
378
                    sink.push_back('\\');
70
378
                    sink.push_back('\"');
71
378
                    count += 2;
72
378
                    break;
73
716
                case '\b':
74
716
                    sink.push_back('\\');
75
716
                    sink.push_back('b');
76
716
                    count += 2;
77
716
                    break;
78
227
                case '\f':
79
227
                    sink.push_back('\\');
80
227
                    sink.push_back('f');
81
227
                    count += 2;
82
227
                    break;
83
279
                case '\n':
84
279
                    sink.push_back('\\');
85
279
                    sink.push_back('n');
86
279
                    count += 2;
87
279
                    break;
88
196
                case '\r':
89
196
                    sink.push_back('\\');
90
196
                    sink.push_back('r');
91
196
                    count += 2;
92
196
                    break;
93
220
                case '\t':
94
220
                    sink.push_back('\\');
95
220
                    sink.push_back('t');
96
220
                    count += 2;
97
220
                    break;
98
3.47M
                default:
99
3.47M
                    if (escape_solidus && c == '/')
100
0
                    {
101
0
                        sink.push_back('\\');
102
0
                        sink.push_back('/');
103
0
                        count += 2;
104
0
                    }
105
3.47M
                    else if (is_control_character(c) || escape_all_non_ascii)
106
172k
                    {
107
                        // convert to codepoint
108
172k
                        uint32_t cp;
109
172k
                        auto r = unicode_traits::to_codepoint(it, end, cp, unicode_traits::conv_flags::strict);
110
172k
                        if (r.ec != unicode_traits::conv_errc())
111
0
                        {
112
0
                            JSONCONS_THROW(ser_error(json_errc::illegal_codepoint));
113
0
                        }
114
172k
                        it = r.ptr - 1;
115
172k
                        if (is_non_ascii_codepoint(cp) || is_control_character(c))
116
172k
                        {
117
172k
                            if (cp > 0xFFFF)
118
0
                            {
119
0
                                cp -= 0x10000;
120
0
                                uint32_t first = (cp >> 10) + 0xD800;
121
0
                                uint32_t second = ((cp & 0x03FF) + 0xDC00);
122
123
0
                                sink.push_back('\\');
124
0
                                sink.push_back('u');
125
0
                                sink.push_back(jsoncons::to_hex_character(first >> 12 & 0x000F));
126
0
                                sink.push_back(jsoncons::to_hex_character(first >> 8 & 0x000F));
127
0
                                sink.push_back(jsoncons::to_hex_character(first >> 4 & 0x000F));
128
0
                                sink.push_back(jsoncons::to_hex_character(first & 0x000F));
129
0
                                sink.push_back('\\');
130
0
                                sink.push_back('u');
131
0
                                sink.push_back(jsoncons::to_hex_character(second >> 12 & 0x000F));
132
0
                                sink.push_back(jsoncons::to_hex_character(second >> 8 & 0x000F));
133
0
                                sink.push_back(jsoncons::to_hex_character(second >> 4 & 0x000F));
134
0
                                sink.push_back(jsoncons::to_hex_character(second & 0x000F));
135
0
                                count += 12;
136
0
                            }
137
172k
                            else
138
172k
                            {
139
172k
                                sink.push_back('\\');
140
172k
                                sink.push_back('u');
141
172k
                                sink.push_back(jsoncons::to_hex_character(cp >> 12 & 0x000F));
142
172k
                                sink.push_back(jsoncons::to_hex_character(cp >> 8 & 0x000F));
143
172k
                                sink.push_back(jsoncons::to_hex_character(cp >> 4 & 0x000F));
144
172k
                                sink.push_back(jsoncons::to_hex_character(cp & 0x000F));
145
172k
                                count += 6;
146
172k
                            }
147
172k
                        }
148
0
                        else
149
0
                        {
150
0
                            sink.push_back(c);
151
0
                            ++count;
152
0
                        }
153
172k
                    }
154
3.30M
                    else
155
3.30M
                    {
156
3.30M
                        sink.push_back(c);
157
3.30M
                        ++count;
158
3.30M
                    }
159
3.47M
                    break;
160
3.48M
            }
161
3.48M
        }
162
273k
        return count;
163
273k
    }
164
165
    inline
166
    byte_string_chars_format resolve_byte_string_chars_format(byte_string_chars_format format1,
167
                                                              byte_string_chars_format format2,
168
                                                              byte_string_chars_format default_format = byte_string_chars_format::base64url)
169
0
    {
170
0
        byte_string_chars_format sink;
171
0
        switch (format1)
172
0
        {
173
0
            case byte_string_chars_format::base16:
174
0
            case byte_string_chars_format::base64:
175
0
            case byte_string_chars_format::base64url:
176
0
                sink = format1;
177
0
                break;
178
0
            default:
179
0
                switch (format2)
180
0
                {
181
0
                    case byte_string_chars_format::base64url:
182
0
                    case byte_string_chars_format::base64:
183
0
                    case byte_string_chars_format::base16:
184
0
                        sink = format2;
185
0
                        break;
186
0
                    default: // base64url
187
0
                    {
188
0
                        sink = default_format;
189
0
                        break;
190
0
                    }
191
0
                }
192
0
                break;
193
0
        }
194
0
        return sink;
195
0
    }
196
197
} // namespace detail
198
199
    template <typename CharT,typename Sink=jsoncons::stream_sink<CharT>,typename Allocator=std::allocator<char>>
200
    class basic_json_encoder final : public basic_json_visitor<CharT>
201
    {
202
        static const jsoncons::basic_string_view<CharT> null_constant()
203
401k
        {
204
401k
            static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "null");
205
401k
            return k;
206
401k
        }
207
        static const jsoncons::basic_string_view<CharT> true_constant()
208
1.63M
        {
209
1.63M
            static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "true");
210
1.63M
            return k;
211
1.63M
        }
212
        static const jsoncons::basic_string_view<CharT> false_constant()
213
806k
        {
214
806k
            static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "false");
215
806k
            return k;
216
806k
        }
217
218
        static const std::array<CharT,1> colon;
219
        static const std::array<CharT,2> colon_space; 
220
        static const std::array<CharT,2> space_colon; 
221
        static const std::array<CharT,3> space_colon_space; 
222
        static const std::array<CharT,1> comma;
223
        static const std::array<CharT,2> comma_space; 
224
        static const std::array<CharT,2> space_comma; 
225
        static const std::array<CharT,3> space_comma_space; 
226
        static const std::array<CharT,1> left_brace; 
227
        static const std::array<CharT,1> right_brace; 
228
        static const std::array<CharT,2> left_brace_space;
229
        static const std::array<CharT,2> space_right_brace; 
230
        static const std::array<CharT,1> left_bracket; 
231
        static const std::array<CharT,1> right_bracket; 
232
        static const std::array<CharT,2> left_bracket_space;
233
        static const std::array<CharT,2> space_right_bracket; 
234
    public:
235
        using allocator_type = Allocator;
236
        using char_type = CharT;
237
        using typename basic_json_visitor<CharT>::string_view_type;
238
        using sink_type = Sink;
239
        using string_type = typename basic_json_encode_options<CharT>::string_type;
240
241
    private:
242
        enum class container_type {object, array};
243
244
        class encoding_context
245
        {
246
            container_type type_;
247
            line_split_kind split_kind_;
248
            bool indent_before_;
249
            bool new_line_after_;
250
            std::size_t begin_pos_{0};
251
            std::size_t data_pos_{0};
252
            std::size_t count_{0};
253
        public:
254
            encoding_context(container_type type, line_split_kind split_lines, bool indent_once,
255
                             std::size_t begin_pos, std::size_t data_pos) noexcept
256
116k
               : type_(type), split_kind_(split_lines), indent_before_(indent_once), new_line_after_(false),
257
116k
                 begin_pos_(begin_pos), data_pos_(data_pos)
258
116k
            {
259
116k
            }
260
261
            encoding_context(const encoding_context&) = default;
262
            
263
            ~encoding_context() = default;
264
            
265
            encoding_context& operator=(const encoding_context&) = default;
266
267
            void set_position(std::size_t pos)
268
3.83k
            {
269
3.83k
                data_pos_ = pos;
270
3.83k
            }
271
272
            std::size_t begin_pos() const
273
            {
274
                return begin_pos_;
275
            }
276
277
            std::size_t data_pos() const
278
0
            {
279
0
                return data_pos_;
280
0
            }
281
282
            std::size_t count() const
283
7.82M
            {
284
7.82M
                return count_;
285
7.82M
            }
286
287
            void increment_count()
288
7.46M
            {
289
7.46M
                ++count_;
290
7.46M
            }
291
292
            bool new_line_after() const
293
28.4k
            {
294
28.4k
                return new_line_after_;
295
28.4k
            }
296
297
            void new_line_after(bool value) 
298
7.55M
            {
299
7.55M
                new_line_after_ = value;
300
7.55M
            }
301
302
            bool is_object() const
303
114k
            {
304
114k
                return type_ == container_type::object;
305
114k
            }
306
307
            bool is_array() const
308
7.55M
            {
309
7.55M
                return type_ == container_type::array;
310
7.55M
            }
311
312
            line_split_kind split_kind() const
313
114k
            {
314
114k
                return split_kind_;
315
114k
            }
316
317
            bool is_multi_line() const
318
14.8M
            {
319
14.8M
                return split_kind_ == line_split_kind::multi_line;
320
14.8M
            }
321
322
            bool is_indent_once() const
323
0
            {
324
0
                return count_ == 0 ? indent_before_ : false;
325
0
            }
326
327
        };
328
        using encoding_context_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<encoding_context>;
329
330
        Sink sink_;
331
        basic_json_encode_options<CharT> options_;
332
        char_type indent_char_{' '};
333
        jsoncons::write_double fp_;
334
335
        std::vector<encoding_context,encoding_context_allocator_type> stack_;
336
        int indent_amount_{0};
337
        std::size_t column_{0};
338
        jsoncons::basic_string_view<CharT> colon_str_;
339
        jsoncons::basic_string_view<CharT> comma_str_;
340
        jsoncons::basic_string_view<CharT> open_brace_str_;
341
        jsoncons::basic_string_view<CharT> close_brace_str_;
342
        jsoncons::basic_string_view<CharT> open_bracket_str_;
343
        jsoncons::basic_string_view<CharT> close_bracket_str_;
344
        int nesting_depth_{0};
345
    public:
346
347
        // Noncopyable and nonmoveable
348
        basic_json_encoder(const basic_json_encoder&) = delete;
349
        basic_json_encoder(basic_json_encoder&&) = delete;
350
351
        basic_json_encoder(Sink&& sink, 
352
                           const Allocator& alloc = Allocator())
353
5.16k
            : basic_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc)
354
5.16k
        {
355
5.16k
        }
356
357
        basic_json_encoder(Sink&& sink, 
358
                           const basic_json_encode_options<CharT>& options, 
359
                           const Allocator& alloc = Allocator())
360
5.16k
           : sink_(std::forward<Sink>(sink)), 
361
5.16k
             options_(options),
362
5.16k
             indent_char_(options.indent_char()),
363
5.16k
             fp_(options.float_format(), options.precision()),
364
5.16k
             stack_(alloc)
365
5.16k
        {
366
5.16k
            switch (options.spaces_around_colon())
367
5.16k
            {
368
5.16k
                case spaces_option::space_after:
369
5.16k
                    colon_str_ = jsoncons::basic_string_view<CharT>(colon_space.data(), colon_space.size());
370
5.16k
                    break;
371
0
                case spaces_option::space_before:
372
0
                    colon_str_ = jsoncons::basic_string_view<CharT>(space_colon.data(), space_colon.size());
373
0
                    break;
374
0
                case spaces_option::space_before_and_after:
375
0
                    colon_str_ = jsoncons::basic_string_view<CharT>(space_colon_space.data(), space_colon_space.size());
376
0
                    break;
377
0
                default:
378
0
                    colon_str_ = jsoncons::basic_string_view<CharT>(colon.data(), colon.size());
379
0
                    break;
380
5.16k
            }
381
5.16k
            switch (options.spaces_around_comma())
382
5.16k
            {
383
5.16k
                case spaces_option::space_after:
384
5.16k
                    comma_str_ = jsoncons::basic_string_view<CharT>(comma_space.data(), colon_space.size());
385
5.16k
                    break;
386
0
                case spaces_option::space_before:
387
0
                    comma_str_ = jsoncons::basic_string_view<CharT>(space_comma.data(), space_comma.size());
388
0
                    break;
389
0
                case spaces_option::space_before_and_after:
390
0
                    comma_str_ = jsoncons::basic_string_view<CharT>(space_comma_space.data(), space_comma_space.size());
391
0
                    break;
392
0
                default:
393
0
                    comma_str_ = jsoncons::basic_string_view<CharT>(comma.data(), comma.size());
394
0
                    break;
395
5.16k
            }
396
5.16k
            if (options.pad_inside_object_braces())
397
0
            {
398
0
                open_brace_str_ = jsoncons::basic_string_view<CharT>(left_brace_space.data(), left_brace_space.size());
399
0
                close_brace_str_ = jsoncons::basic_string_view<CharT>(space_right_brace.data(), space_right_brace.size());
400
0
            }
401
5.16k
            else
402
5.16k
            {
403
5.16k
                open_brace_str_ = jsoncons::basic_string_view<CharT>(left_brace.data(), left_brace.size());
404
5.16k
                close_brace_str_ = jsoncons::basic_string_view<CharT>(right_brace.data(), right_brace.size());
405
5.16k
            }
406
5.16k
            if (options.pad_inside_array_brackets())
407
0
            {
408
0
                open_bracket_str_ = jsoncons::basic_string_view<CharT>(left_bracket_space.data(), left_bracket_space.size());
409
0
                close_bracket_str_ = jsoncons::basic_string_view<CharT>(space_right_bracket.data(), space_right_bracket.size());
410
0
            }
411
5.16k
            else
412
5.16k
            {
413
5.16k
                open_bracket_str_ = jsoncons::basic_string_view<CharT>(left_bracket.data(), left_bracket.size());
414
5.16k
                close_bracket_str_ = jsoncons::basic_string_view<CharT>(right_bracket.data(), right_bracket.size());
415
5.16k
            }
416
5.16k
        }
417
418
        ~basic_json_encoder() noexcept
419
5.16k
        {
420
5.16k
            JSONCONS_TRY
421
5.16k
            {
422
5.16k
                sink_.flush();
423
5.16k
            }
424
5.16k
            JSONCONS_CATCH(...)
425
5.16k
            {
426
0
            }
427
5.16k
        }
428
429
        basic_json_encoder& operator=(const basic_json_encoder&) = delete;
430
        basic_json_encoder& operator=(basic_json_encoder&&) = delete;
431
432
        void reset()
433
        {
434
            stack_.clear();
435
            indent_amount_ = 0;
436
            column_ = 0;
437
            nesting_depth_ = 0;
438
        }
439
440
        void reset(Sink&& sink)
441
        {
442
            sink_ = std::move(sink);
443
            reset();
444
        }
445
446
    private:
447
        // Implementing methods
448
        void visit_flush() final
449
1.85k
        {
450
1.85k
            sink_.flush();
451
1.85k
        }
452
453
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) final
454
22.0k
        {
455
22.0k
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
456
0
            {
457
0
                ec = json_errc::max_nesting_depth_exceeded;
458
0
                JSONCONS_VISITOR_RETURN;
459
0
            } 
460
22.0k
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
461
19.0k
            {
462
19.0k
                sink_.append(comma_str_.data(),comma_str_.length());
463
19.0k
                column_ += comma_str_.length();
464
19.0k
            }
465
466
22.0k
            if (!stack_.empty()) // object or array
467
21.6k
            {
468
21.6k
                if (stack_.back().is_object())
469
1.31k
                {
470
1.31k
                    line_split_kind split_kind = static_cast<uint8_t>(options_.object_object_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
471
1.31k
                        options_.object_object_line_splits() : stack_.back().split_kind();
472
1.31k
                    switch (split_kind)
473
1.31k
                    {
474
0
                        case line_split_kind::same_line:
475
0
                        case line_split_kind::new_line:
476
0
                            if (column_ >= options_.line_length_limit())
477
0
                            {
478
0
                                break_line();
479
0
                            }
480
0
                            break;
481
1.31k
                        default: // multi_line
482
1.31k
                            break;
483
1.31k
                    }
484
1.31k
                    stack_.emplace_back(container_type::object,split_kind, false,
485
1.31k
                                        column_, column_+open_brace_str_.length());
486
1.31k
                }
487
20.3k
                else // array
488
20.3k
                {
489
20.3k
                    line_split_kind split_kind = static_cast<uint8_t>(options_.array_object_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
490
20.3k
                        options_.array_object_line_splits() : stack_.back().split_kind();
491
20.3k
                    switch (split_kind)
492
20.3k
                    {
493
0
                        case line_split_kind::same_line:
494
0
                            if (column_ >= options_.line_length_limit())
495
0
                            {
496
                                //stack_.back().new_line_after(true);
497
0
                                new_line();
498
0
                            }
499
0
                            else
500
0
                            {
501
0
                                stack_.back().new_line_after(true);
502
0
                                new_line();
503
0
                            }
504
0
                            break;
505
0
                        case line_split_kind::new_line:
506
0
                            stack_.back().new_line_after(true);
507
0
                            new_line();
508
0
                            break;
509
20.3k
                        default: // multi_line
510
20.3k
                            stack_.back().new_line_after(true);
511
20.3k
                            new_line();
512
20.3k
                            break;
513
20.3k
                    }
514
20.3k
                    stack_.emplace_back(container_type::object,split_kind, false,
515
20.3k
                                        column_, column_+open_brace_str_.length());
516
20.3k
                }
517
21.6k
            }
518
463
            else 
519
463
            {
520
463
                stack_.emplace_back(container_type::object, options_.root_line_splits(), false,
521
463
                                    column_, column_+open_brace_str_.length());
522
463
            }
523
22.0k
            indent();
524
            
525
22.0k
            sink_.append(open_brace_str_.data(), open_brace_str_.length());
526
22.0k
            column_ += open_brace_str_.length();
527
22.0k
            JSONCONS_VISITOR_RETURN;
528
22.0k
        }
529
530
        JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code&) final
531
19.8k
        {
532
19.8k
            JSONCONS_ASSERT(!stack_.empty());
533
19.8k
            --nesting_depth_;
534
535
19.8k
            unindent();
536
19.8k
            if (stack_.back().new_line_after())
537
1.73k
            {
538
1.73k
                new_line();
539
1.73k
            }
540
19.8k
            stack_.pop_back();
541
19.8k
            sink_.append(close_brace_str_.data(), close_brace_str_.length());
542
19.8k
            column_ += close_brace_str_.length();
543
544
19.8k
            end_value();
545
19.8k
            JSONCONS_VISITOR_RETURN;
546
19.8k
        }
547
548
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) final
549
94.7k
        {
550
94.7k
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
551
0
            {
552
0
                ec = json_errc::max_nesting_depth_exceeded;
553
0
                JSONCONS_VISITOR_RETURN;
554
0
            } 
555
94.7k
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
556
28.7k
            {
557
28.7k
                sink_.append(comma_str_.data(),comma_str_.length());
558
28.7k
                column_ += comma_str_.length();
559
28.7k
            }
560
94.7k
            if (!stack_.empty())
561
93.0k
            {
562
93.0k
                if (stack_.back().is_object())
563
755
                {
564
755
                    line_split_kind split_kind = static_cast<uint8_t>(options_.object_array_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
565
755
                        options_.object_array_line_splits() : 
566
755
                        stack_.back().split_kind();
567
755
                    switch (split_kind)
568
755
                    {
569
0
                        case line_split_kind::same_line:
570
0
                            stack_.emplace_back(container_type::array,split_kind,false,
571
0
                                                column_, column_ + open_bracket_str_.length());
572
0
                            break;
573
0
                        case line_split_kind::new_line:
574
0
                        {
575
0
                            stack_.emplace_back(container_type::array,split_kind,true,
576
0
                                                column_, column_+open_bracket_str_.length());
577
0
                            break;
578
0
                        }
579
755
                        default: // multi_line
580
755
                            stack_.emplace_back(container_type::array,split_kind,true,
581
755
                                                column_, column_+open_bracket_str_.length());
582
755
                            break;
583
755
                    }
584
755
                }
585
92.2k
                else // array
586
92.2k
                {
587
92.2k
                    line_split_kind split_kind = static_cast<uint8_t>(options_.array_array_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
588
92.2k
                        options_.array_array_line_splits() : stack_.back().split_kind();
589
92.2k
                    switch (split_kind)
590
92.2k
                    {
591
0
                        case line_split_kind::same_line:
592
0
                            if (stack_.back().is_multi_line())
593
0
                            {
594
0
                                stack_.back().new_line_after(true);
595
0
                                new_line();
596
0
                            }
597
0
                            stack_.emplace_back(container_type::array,split_kind, false,
598
0
                                                column_, column_+open_bracket_str_.length());
599
0
                            break;
600
0
                        case line_split_kind::new_line:
601
0
                            stack_.back().new_line_after(true);
602
0
                            new_line();
603
0
                            stack_.emplace_back(container_type::array,split_kind, true,
604
0
                                                column_, column_+open_bracket_str_.length());
605
0
                            break;
606
92.2k
                        default: // multi_line
607
92.2k
                            stack_.back().new_line_after(true);
608
92.2k
                            new_line();
609
92.2k
                            stack_.emplace_back(container_type::array,split_kind, false,
610
92.2k
                                                column_, column_+open_bracket_str_.length());
611
92.2k
                            break;
612
92.2k
                    }
613
92.2k
                }
614
93.0k
            }
615
1.71k
            else 
616
1.71k
            {
617
1.71k
                stack_.emplace_back(container_type::array, options_.root_line_splits(), false,
618
1.71k
                                    column_, column_+open_bracket_str_.length());
619
1.71k
            }
620
94.7k
            indent();
621
94.7k
            sink_.append(open_bracket_str_.data(), open_bracket_str_.length());
622
94.7k
            column_ += open_bracket_str_.length();
623
94.7k
            JSONCONS_VISITOR_RETURN;
624
94.7k
        }
625
626
        JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code&) final
627
8.64k
        {
628
8.64k
            JSONCONS_ASSERT(!stack_.empty());
629
8.64k
            --nesting_depth_;
630
631
8.64k
            unindent();
632
8.64k
            if (stack_.back().new_line_after())
633
7.75k
            {
634
7.75k
                new_line();
635
7.75k
            }
636
8.64k
            stack_.pop_back();
637
8.64k
            sink_.append(close_bracket_str_.data(), close_bracket_str_.length());
638
8.64k
            column_ += close_bracket_str_.length();
639
8.64k
            end_value();
640
8.64k
            JSONCONS_VISITOR_RETURN;
641
8.64k
        }
642
643
        JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context&, std::error_code&) final
644
272k
        {
645
272k
            JSONCONS_ASSERT(!stack_.empty());
646
272k
            if (stack_.back().count() > 0)
647
269k
            {
648
269k
                sink_.append(comma_str_.data(),comma_str_.length());
649
269k
                column_ += comma_str_.length();
650
269k
            }
651
652
272k
            if (stack_.back().is_multi_line())
653
272k
            {
654
272k
                stack_.back().new_line_after(true);
655
272k
                new_line();
656
272k
            }
657
0
            else if (stack_.back().count() > 0 && column_ >= options_.line_length_limit())
658
0
            {
659
                //stack_.back().new_line_after(true);
660
0
                new_line(stack_.back().data_pos());
661
0
            }
662
663
272k
            if (stack_.back().count() == 0)
664
3.83k
            {
665
3.83k
                stack_.back().set_position(column_);
666
3.83k
            }
667
272k
            sink_.push_back('\"');
668
272k
            std::size_t length = jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
669
272k
            sink_.push_back('\"');
670
272k
            sink_.append(colon_str_.data(),colon_str_.length());
671
272k
            column_ += (length+2+colon_str_.length());
672
272k
            JSONCONS_VISITOR_RETURN;
673
272k
        }
674
675
        JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final
676
133k
        {
677
133k
            if (!stack_.empty()) 
678
133k
            {
679
133k
                if (stack_.back().is_array())
680
133k
                {
681
133k
                    begin_scalar_value();
682
133k
                }
683
133k
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
684
0
                {
685
0
                    break_line();
686
0
                }
687
133k
            }
688
689
133k
            sink_.append(null_constant().data(), null_constant().size());
690
133k
            column_ += null_constant().size();
691
692
133k
            end_value();
693
133k
            JSONCONS_VISITOR_RETURN;
694
133k
        }
695
696
        JSONCONS_VISITOR_RETURN_TYPE visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) final
697
25.3k
        {
698
25.3k
            if (!stack_.empty()) 
699
24.8k
            {
700
24.8k
                if (stack_.back().is_array())
701
24.5k
                {
702
24.5k
                    begin_scalar_value();
703
24.5k
                }
704
24.8k
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
705
0
                {
706
0
                    break_line();
707
0
                }
708
24.8k
            }
709
            
710
25.3k
            write_string(sv, tag, context, ec);
711
712
25.3k
            end_value();
713
25.3k
            JSONCONS_VISITOR_RETURN;
714
25.3k
        }
715
716
        void write_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) 
717
25.3k
        {
718
25.3k
            if (JSONCONS_LIKELY(tag == semantic_tag::noesc && !options_.escape_all_non_ascii() && !options_.escape_solidus()))
719
12.6k
            {
720
                //std::cout << "noesc\n";
721
12.6k
                sink_.push_back('\"');
722
12.6k
                const CharT* begin = sv.data();
723
12.6k
                const CharT* end = begin + sv.length();
724
1.34M
                for (const CharT* it = begin; it != end; ++it)
725
1.33M
                {
726
1.33M
                    sink_.push_back(*it);
727
1.33M
                }
728
12.6k
                sink_.push_back('\"');
729
12.6k
                column_ += (sv.length()+2);
730
12.6k
            }
731
12.6k
            else if (tag == semantic_tag::bigint)
732
10.7k
            {
733
10.7k
                write_bignum_value(sv);
734
10.7k
            }
735
1.90k
            else if (tag == semantic_tag::bigdec && options_.bignum_format() == bignum_format_kind::raw)
736
1.02k
            {
737
1.02k
                write_bignum_value(sv);
738
1.02k
            }
739
878
            else
740
878
            {
741
                //if (tag != semantic_tag::bigdec)
742
                //    std::cout << "esc\n";
743
878
                sink_.push_back('\"');
744
878
                std::size_t length = jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
745
878
                sink_.push_back('\"');
746
878
                column_ += (length+2);
747
878
            }           
748
25.3k
        }
749
750
        JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, 
751
                                  semantic_tag tag,
752
                                  const ser_context&,
753
                                  std::error_code&) final
754
0
        {
755
0
            if (!stack_.empty()) 
756
0
            {
757
0
                if (stack_.back().is_array())
758
0
                {
759
0
                    begin_scalar_value();
760
0
                }
761
0
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
762
0
                {
763
0
                    break_line();
764
0
                }
765
0
            }
766
767
0
            byte_string_chars_format encoding_hint;
768
0
            switch (tag)
769
0
            {
770
0
                case semantic_tag::base16:
771
0
                    encoding_hint = byte_string_chars_format::base16;
772
0
                    break;
773
0
                case semantic_tag::base64:
774
0
                    encoding_hint = byte_string_chars_format::base64;
775
0
                    break;
776
0
                case semantic_tag::base64url:
777
0
                    encoding_hint = byte_string_chars_format::base64url;
778
0
                    break;
779
0
                default:
780
0
                    encoding_hint = byte_string_chars_format::none;
781
0
                    break;
782
0
            }
783
784
0
            byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), 
785
0
                                                                                                 encoding_hint, 
786
0
                                                                                                 byte_string_chars_format::base64url);
787
0
            switch (format)
788
0
            {
789
0
                case byte_string_chars_format::base16:
790
0
                {
791
0
                    sink_.push_back('\"');
792
0
                    std::size_t length = bytes_to_base16(b.begin(),b.end(),sink_);
793
0
                    sink_.push_back('\"');
794
0
                    column_ += (length + 2);
795
0
                    break;
796
0
                }
797
0
                case byte_string_chars_format::base64:
798
0
                {
799
0
                    sink_.push_back('\"');
800
0
                    std::size_t length = bytes_to_base64(b.begin(), b.end(), sink_);
801
0
                    sink_.push_back('\"');
802
0
                    column_ += (length + 2);
803
0
                    break;
804
0
                }
805
0
                case byte_string_chars_format::base64url:
806
0
                {
807
0
                    sink_.push_back('\"');
808
0
                    std::size_t length = bytes_to_base64url(b.begin(),b.end(),sink_);
809
0
                    sink_.push_back('\"');
810
0
                    column_ += (length + 2);
811
0
                    break;
812
0
                }
813
0
                default:
814
0
                {
815
0
                    JSONCONS_UNREACHABLE();
816
0
                }
817
0
            }
818
819
0
            end_value();
820
0
            JSONCONS_VISITOR_RETURN;
821
0
        }
822
823
        JSONCONS_VISITOR_RETURN_TYPE visit_double(double value, 
824
                             semantic_tag,
825
                             const ser_context& context,
826
                             std::error_code& ec) final
827
1.34M
        {
828
1.34M
            if (!stack_.empty()) 
829
1.34M
            {
830
1.34M
                if (stack_.back().is_array())
831
1.34M
                {
832
1.34M
                    begin_scalar_value();
833
1.34M
                }
834
1.34M
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
835
0
                {
836
0
                    break_line();
837
0
                }
838
1.34M
            }
839
840
1.34M
            if (!std::isfinite(value))
841
0
            {
842
0
                if ((std::isnan)(value))
843
0
                {
844
0
                    if (options_.enable_nan_to_num())
845
0
                    {
846
0
                        sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length());
847
0
                        column_ += options_.nan_to_num().length();
848
0
                    }
849
0
                    else if (options_.enable_nan_to_str())
850
0
                    {
851
0
                        write_string(options_.nan_to_str(), semantic_tag::none, context, ec);
852
0
                    }
853
0
                    else
854
0
                    {
855
0
                        sink_.append(null_constant().data(), null_constant().size());
856
0
                        column_ += null_constant().size();
857
0
                    }
858
0
                }
859
0
                else if (value == std::numeric_limits<double>::infinity())
860
0
                {
861
0
                    if (options_.enable_inf_to_num())
862
0
                    {
863
0
                        sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length());
864
0
                        column_ += options_.inf_to_num().length();
865
0
                    }
866
0
                    else if (options_.enable_inf_to_str())
867
0
                    {
868
0
                        write_string(options_.inf_to_str(), semantic_tag::none, context, ec);
869
0
                    }
870
0
                    else
871
0
                    {
872
0
                        sink_.append(null_constant().data(), null_constant().size());
873
0
                        column_ += null_constant().size();
874
0
                    }
875
0
                }
876
0
                else
877
0
                {
878
0
                    if (options_.enable_neginf_to_num())
879
0
                    {
880
0
                        sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length());
881
0
                        column_ += options_.neginf_to_num().length();
882
0
                    }
883
0
                    else if (options_.enable_neginf_to_str())
884
0
                    {
885
0
                        write_string(options_.neginf_to_str(), semantic_tag::none, context, ec);
886
0
                    }
887
0
                    else
888
0
                    {
889
0
                        sink_.append(null_constant().data(), null_constant().size());
890
0
                        column_ += null_constant().size();
891
0
                    }
892
0
                }
893
0
            }
894
1.34M
            else
895
1.34M
            {
896
1.34M
                std::size_t length = fp_(value, sink_);
897
1.34M
                column_ += length;
898
1.34M
            }
899
900
1.34M
            end_value();
901
1.34M
            JSONCONS_VISITOR_RETURN;
902
1.34M
        }
903
904
        JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t value, 
905
                            semantic_tag,
906
                            const ser_context&,
907
                            std::error_code&) final
908
228k
        {
909
228k
            if (!stack_.empty()) 
910
227k
            {
911
227k
                if (stack_.back().is_array())
912
227k
                {
913
227k
                    begin_scalar_value();
914
227k
                }
915
227k
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
916
0
                {
917
0
                    break_line();
918
0
                }
919
227k
            }
920
228k
            std::size_t length = jsoncons::from_integer(value, sink_);
921
228k
            column_ += length;
922
228k
            end_value();
923
228k
            JSONCONS_VISITOR_RETURN;
924
228k
        }
925
926
        JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t value, 
927
                             semantic_tag, 
928
                             const ser_context&,
929
                             std::error_code&) final
930
4.89M
        {
931
4.89M
            if (!stack_.empty()) 
932
4.89M
            {
933
4.89M
                if (stack_.back().is_array())
934
4.62M
                {
935
4.62M
                    begin_scalar_value();
936
4.62M
                }
937
4.89M
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
938
0
                {
939
0
                    break_line();
940
0
                }
941
4.89M
            }
942
4.89M
            std::size_t length = jsoncons::from_integer(value, sink_);
943
4.89M
            column_ += length;
944
4.89M
            end_value();
945
4.89M
            JSONCONS_VISITOR_RETURN;
946
4.89M
        }
947
948
        JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) final
949
812k
        {
950
812k
            if (!stack_.empty()) 
951
812k
            {
952
812k
                if (stack_.back().is_array())
953
812k
                {
954
812k
                    begin_scalar_value();
955
812k
                }
956
812k
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
957
0
                {
958
0
                    break_line();
959
0
                }
960
812k
            }
961
962
812k
            if (value)
963
543k
            {
964
543k
                sink_.append(true_constant().data(), true_constant().size());
965
543k
                column_ += true_constant().size();
966
543k
            }
967
268k
            else
968
268k
            {
969
268k
                sink_.append(false_constant().data(), false_constant().size());
970
268k
                column_ += false_constant().size();
971
268k
            }
972
973
812k
            end_value();
974
812k
            JSONCONS_VISITOR_RETURN;
975
812k
        }
976
977
        void begin_scalar_value()
978
7.16M
        {
979
7.16M
            if (!stack_.empty())
980
7.16M
            {
981
7.16M
                if (stack_.back().count() > 0)
982
7.13M
                {
983
7.13M
                    sink_.append(comma_str_.data(),comma_str_.length());
984
7.13M
                    column_ += comma_str_.length();
985
7.13M
                }
986
7.16M
                if (stack_.back().is_multi_line() || stack_.back().is_indent_once())
987
7.16M
                {
988
7.16M
                    stack_.back().new_line_after(true);
989
7.16M
                    new_line();
990
7.16M
                }
991
7.16M
            }
992
7.16M
        }
993
994
        void write_bignum_value(const string_view_type& sv)
995
11.7k
        {
996
11.7k
            switch (options_.bignum_format())
997
11.7k
            {
998
11.7k
                case bignum_format_kind::raw:
999
11.7k
                {
1000
11.7k
                    sink_.append(sv.data(),sv.size());
1001
11.7k
                    column_ += sv.size();
1002
11.7k
                    break;
1003
0
                }
1004
0
                case bignum_format_kind::base64:
1005
0
                {
1006
0
                    bigint n(sv.data(), sv.length());
1007
0
                    bool is_neg = n < 0;
1008
0
                    if (is_neg)
1009
0
                    {
1010
0
                        n = - n -1;
1011
0
                    }
1012
0
                    int signum;
1013
0
                    std::vector<uint8_t> v;
1014
0
                    n.write_bytes_be(signum, v);
1015
1016
0
                    sink_.push_back('\"');
1017
0
                    if (is_neg)
1018
0
                    {
1019
0
                        sink_.push_back('~');
1020
0
                        ++column_;
1021
0
                    }
1022
0
                    std::size_t length = bytes_to_base64(v.begin(), v.end(), sink_);
1023
0
                    sink_.push_back('\"');
1024
0
                    column_ += (length+2);
1025
0
                    break;
1026
0
                }
1027
0
                case bignum_format_kind::base64url:
1028
0
                {
1029
0
                    bigint n(sv.data(), sv.length());
1030
0
                    bool is_neg = n < 0;
1031
0
                    if (is_neg)
1032
0
                    {
1033
0
                        n = - n -1;
1034
0
                    }
1035
0
                    int signum;
1036
0
                    std::vector<uint8_t> v;
1037
0
                    n.write_bytes_be(signum, v);
1038
1039
0
                    sink_.push_back('\"');
1040
0
                    if (is_neg)
1041
0
                    {
1042
0
                        sink_.push_back('~');
1043
0
                        ++column_;
1044
0
                    }
1045
0
                    std::size_t length = bytes_to_base64url(v.begin(), v.end(), sink_);
1046
0
                    sink_.push_back('\"');
1047
0
                    column_ += (length+2);
1048
0
                    break;
1049
0
                }
1050
0
                default:
1051
0
                {
1052
0
                    sink_.push_back('\"');
1053
0
                    sink_.append(sv.data(),sv.size());
1054
0
                    sink_.push_back('\"');
1055
0
                    column_ += (sv.size() + 2);
1056
0
                    break;
1057
0
                }
1058
11.7k
            }
1059
11.7k
        }
1060
1061
        void end_value()
1062
7.46M
        {
1063
7.46M
            if (!stack_.empty())
1064
7.46M
            {
1065
7.46M
                stack_.back().increment_count();
1066
7.46M
            }
1067
7.46M
        }
1068
1069
        void indent()
1070
116k
        {
1071
116k
            indent_amount_ += static_cast<uint8_t>(options_.indent_size());
1072
116k
        }
1073
1074
        void unindent()
1075
28.4k
        {
1076
28.4k
            indent_amount_ -= static_cast<uint8_t>(options_.indent_size());
1077
28.4k
        }
1078
1079
        void new_line()
1080
7.56M
        {
1081
7.56M
            sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length());
1082
2.39G
            for (int i = 0; i < indent_amount_; ++i)
1083
2.39G
            {
1084
2.39G
                sink_.push_back(indent_char_);
1085
2.39G
            }
1086
7.56M
            column_ = indent_amount_;
1087
7.56M
        }
1088
1089
        void new_line(std::size_t len)
1090
0
        {
1091
0
            sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length());
1092
0
            for (std::size_t i = 0; i < len; ++i)
1093
0
            {
1094
0
                sink_.push_back(' ');
1095
0
            }
1096
0
            column_ = len;
1097
0
        }
1098
1099
        void break_line()
1100
0
        {
1101
0
            stack_.back().new_line_after(true);
1102
0
            new_line();
1103
0
        }
1104
    };
1105
1106
    template <typename CharT, typename Sink, typename Allocator>
1107
    const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::colon = {':'};
1108
    template <typename CharT,typename Sink,typename Allocator>
1109
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::colon_space = {':', ' '};
1110
    template <typename CharT,typename Sink,typename Allocator>
1111
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_colon = {' ', ':'};
1112
    template <typename CharT,typename Sink,typename Allocator>
1113
    const std::array<CharT,3> basic_json_encoder<CharT,Sink,Allocator>::space_colon_space = {' ', ':', ' '};
1114
1115
    template <typename CharT, typename Sink, typename Allocator>
1116
    const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::comma = {','};
1117
    template <typename CharT,typename Sink,typename Allocator>
1118
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::comma_space = {',', ' '};
1119
    template <typename CharT,typename Sink,typename Allocator>
1120
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_comma = {' ', ','};
1121
    template <typename CharT,typename Sink,typename Allocator>
1122
    const std::array<CharT,3> basic_json_encoder<CharT,Sink,Allocator>::space_comma_space = {' ', ',', ' '};
1123
1124
    template <typename CharT, typename Sink, typename Allocator>
1125
    const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::left_brace = {'{'};
1126
    template <typename CharT,typename Sink,typename Allocator>
1127
    const std::array<CharT,1> basic_json_encoder<CharT,Sink,Allocator>::right_brace = {'}'};
1128
    template <typename CharT,typename Sink,typename Allocator>
1129
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::left_brace_space = {'{', ' '};
1130
    template <typename CharT,typename Sink,typename Allocator>
1131
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_right_brace = {' ', '}'};
1132
1133
    template <typename CharT, typename Sink, typename Allocator>
1134
    const std::array<CharT,1> basic_json_encoder<CharT, Sink, Allocator>::left_bracket = {'['};
1135
    template <typename CharT,typename Sink,typename Allocator>
1136
    const std::array<CharT,1> basic_json_encoder<CharT,Sink,Allocator>::right_bracket = {']'};
1137
    template <typename CharT,typename Sink,typename Allocator>
1138
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::left_bracket_space = {'[', ' '};
1139
    template <typename CharT,typename Sink,typename Allocator>
1140
    const std::array<CharT,2> basic_json_encoder<CharT,Sink,Allocator>::space_right_bracket = {' ', ']'};
1141
1142
    template <typename CharT,typename Sink=jsoncons::stream_sink<CharT>,typename Allocator=std::allocator<char>>
1143
    class basic_compact_json_encoder final : public basic_json_visitor<CharT>
1144
    {
1145
        static const std::array<CharT, 4>& null_constant()
1146
        {
1147
            static constexpr std::array<CharT,4> k{{'n','u','l','l'}};
1148
            return k;
1149
        }
1150
        static const std::array<CharT, 4>& true_constant()
1151
        {
1152
            static constexpr std::array<CharT,4> k{{'t','r','u','e'}};
1153
            return k;
1154
        }
1155
        static const std::array<CharT, 5>& false_constant()
1156
        {
1157
            static constexpr std::array<CharT,5> k{{'f','a','l','s','e'}};
1158
            return k;
1159
        }
1160
    public:
1161
        using allocator_type = Allocator;
1162
        using char_type = CharT;
1163
        using typename basic_json_visitor<CharT>::string_view_type;
1164
        using sink_type = Sink;
1165
        using string_type = typename basic_json_encode_options<CharT>::string_type;
1166
1167
    private:
1168
        enum class container_type {object, array};
1169
1170
        class encoding_context
1171
        {
1172
            container_type type_;
1173
            std::size_t count_{0};
1174
        public:
1175
            encoding_context(container_type type) noexcept
1176
               : type_(type)
1177
            {
1178
            }
1179
1180
            std::size_t count() const
1181
            {
1182
                return count_;
1183
            }
1184
1185
            void increment_count()
1186
            {
1187
                ++count_;
1188
            }
1189
1190
            bool is_array() const
1191
            {
1192
                return type_ == container_type::array;
1193
            }
1194
        };
1195
        using encoding_context_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<encoding_context>;
1196
1197
        Sink sink_;
1198
        basic_json_encode_options<CharT> options_;
1199
        jsoncons::write_double fp_;
1200
        std::vector<encoding_context,encoding_context_allocator_type> stack_;
1201
        int nesting_depth_;
1202
    public:
1203
1204
        // Noncopyable and nonmoveable
1205
        basic_compact_json_encoder(const basic_compact_json_encoder&) = delete;
1206
        basic_compact_json_encoder(basic_compact_json_encoder&&) = delete;
1207
1208
        basic_compact_json_encoder(Sink&& sink, 
1209
            const Allocator& alloc = Allocator())
1210
            : basic_compact_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc)
1211
        {
1212
        }
1213
1214
        basic_compact_json_encoder(Sink&& sink, 
1215
            const basic_json_encode_options<CharT>& options, 
1216
            const Allocator& alloc = Allocator())
1217
           : sink_(std::forward<Sink>(sink)),
1218
             options_(options),
1219
             fp_(options.float_format(), options.precision()),
1220
             stack_(alloc),
1221
             nesting_depth_(0)          
1222
        {
1223
        }
1224
1225
        ~basic_compact_json_encoder() noexcept
1226
        {
1227
            JSONCONS_TRY
1228
            {
1229
                sink_.flush();
1230
            }
1231
            JSONCONS_CATCH(...)
1232
            {
1233
            }
1234
        }
1235
1236
        basic_compact_json_encoder& operator=(const basic_compact_json_encoder&) = delete;
1237
        basic_compact_json_encoder& operator=(basic_compact_json_encoder&&) = delete;
1238
1239
        void reset()
1240
        {
1241
            stack_.clear();
1242
            nesting_depth_ = 0;
1243
        }
1244
1245
        void reset(Sink&& sink)
1246
        {
1247
            sink_ = std::move(sink);
1248
            reset();
1249
        }
1250
1251
    private:
1252
        // Implementing methods
1253
        void visit_flush() final
1254
        {
1255
            sink_.flush();
1256
        }
1257
1258
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) final
1259
        {
1260
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
1261
            {
1262
                ec = json_errc::max_nesting_depth_exceeded;
1263
                JSONCONS_VISITOR_RETURN;
1264
            } 
1265
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1266
            {
1267
                sink_.push_back(',');
1268
            }
1269
1270
            stack_.emplace_back(container_type::object);
1271
            sink_.push_back('{');
1272
            JSONCONS_VISITOR_RETURN;
1273
        }
1274
1275
        JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code&) final
1276
        {
1277
            JSONCONS_ASSERT(!stack_.empty());
1278
            --nesting_depth_;
1279
1280
            stack_.pop_back();
1281
            sink_.push_back('}');
1282
1283
            if (!stack_.empty())
1284
            {
1285
                stack_.back().increment_count();
1286
            }
1287
            JSONCONS_VISITOR_RETURN;
1288
        }
1289
1290
1291
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) final
1292
        {
1293
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
1294
            {
1295
                ec = json_errc::max_nesting_depth_exceeded;
1296
                JSONCONS_VISITOR_RETURN;
1297
            } 
1298
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1299
            {
1300
                sink_.push_back(',');
1301
            }
1302
            stack_.emplace_back(container_type::array);
1303
            sink_.push_back('[');
1304
            JSONCONS_VISITOR_RETURN;
1305
        }
1306
1307
        JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code&) final
1308
        {
1309
            JSONCONS_ASSERT(!stack_.empty());
1310
            --nesting_depth_;
1311
1312
            stack_.pop_back();
1313
            sink_.push_back(']');
1314
            if (!stack_.empty())
1315
            {
1316
                stack_.back().increment_count();
1317
            }
1318
            JSONCONS_VISITOR_RETURN;
1319
        }
1320
1321
        JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context&, std::error_code&) final
1322
        {
1323
            if (!stack_.empty() && stack_.back().count() > 0)
1324
            {
1325
                sink_.push_back(',');
1326
            }
1327
1328
            sink_.push_back('\"');
1329
            jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
1330
            sink_.push_back('\"');
1331
            sink_.push_back(':');
1332
            JSONCONS_VISITOR_RETURN;
1333
        }
1334
1335
        JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final
1336
        {
1337
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1338
            {
1339
                sink_.push_back(',');
1340
            }
1341
1342
            sink_.append(null_constant().data(), null_constant().size());
1343
1344
            if (!stack_.empty())
1345
            {
1346
                stack_.back().increment_count();
1347
            }
1348
            JSONCONS_VISITOR_RETURN;
1349
        }
1350
1351
        void write_bignum_value(const string_view_type& sv)
1352
        {
1353
            switch (options_.bignum_format())
1354
            {
1355
                case bignum_format_kind::raw:
1356
                {
1357
                    sink_.append(sv.data(),sv.size());
1358
                    break;
1359
                }
1360
                case bignum_format_kind::base64:
1361
                {
1362
                    bigint n(sv.data(), sv.length());
1363
                    bool is_neg = n < 0;
1364
                    if (is_neg)
1365
                    {
1366
                        n = - n -1;
1367
                    }
1368
                    int signum;
1369
                    std::vector<uint8_t> v;
1370
                    n.write_bytes_be(signum, v);
1371
1372
                    sink_.push_back('\"');
1373
                    if (is_neg)
1374
                    {
1375
                        sink_.push_back('~');
1376
                    }
1377
                    bytes_to_base64(v.begin(), v.end(), sink_);
1378
                    sink_.push_back('\"');
1379
                    break;
1380
                }
1381
                case bignum_format_kind::base64url:
1382
                {
1383
                    bigint n(sv.data(), sv.length());
1384
                    bool is_neg = n < 0;
1385
                    if (is_neg)
1386
                    {
1387
                        n = - n -1;
1388
                    }
1389
                    int signum;
1390
                    std::vector<uint8_t> v;
1391
                    n.write_bytes_be(signum, v);
1392
1393
                    sink_.push_back('\"');
1394
                    if (is_neg)
1395
                    {
1396
                        sink_.push_back('~');
1397
                    }
1398
                    bytes_to_base64url(v.begin(), v.end(), sink_);
1399
                    sink_.push_back('\"');
1400
                    break;
1401
                }
1402
                default:
1403
                {
1404
                    sink_.push_back('\"');
1405
                    sink_.append(sv.data(),sv.size());
1406
                    sink_.push_back('\"');
1407
                    break;
1408
                }
1409
            }
1410
        }
1411
1412
        JSONCONS_VISITOR_RETURN_TYPE visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) final
1413
        {
1414
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1415
            {
1416
                sink_.push_back(',');
1417
            }
1418
1419
            write_string(sv, tag, context, ec);
1420
1421
            if (!stack_.empty())
1422
            {
1423
                stack_.back().increment_count();
1424
            }
1425
            JSONCONS_VISITOR_RETURN;
1426
        }
1427
1428
        void write_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) 
1429
        {
1430
            if (JSONCONS_LIKELY(tag == semantic_tag::noesc && !options_.escape_all_non_ascii() && !options_.escape_solidus()))
1431
            {
1432
                //std::cout << "noesc\n";
1433
                sink_.push_back('\"');
1434
                const CharT* begin = sv.data();
1435
                const CharT* end = begin + sv.length();
1436
                for (const CharT* it = begin; it != end; ++it)
1437
                {
1438
                    sink_.push_back(*it);
1439
                }
1440
                sink_.push_back('\"');
1441
            }
1442
            else if (tag == semantic_tag::bigint)
1443
            {
1444
                write_bignum_value(sv);
1445
            }
1446
            else if (tag == semantic_tag::bigdec && options_.bignum_format() == bignum_format_kind::raw)
1447
            {
1448
                write_bignum_value(sv);
1449
            }
1450
            else
1451
            {
1452
                //if (tag != semantic_tag::bigdec)
1453
                //    std::cout << "esc\n";
1454
                sink_.push_back('\"');
1455
                jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
1456
                sink_.push_back('\"');
1457
            }           
1458
        }
1459
1460
        JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, 
1461
            semantic_tag tag,
1462
            const ser_context&,
1463
            std::error_code&) final
1464
        {
1465
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1466
            {
1467
                sink_.push_back(',');
1468
            }
1469
1470
            byte_string_chars_format encoding_hint;
1471
            switch (tag)
1472
            {
1473
                case semantic_tag::base16:
1474
                    encoding_hint = byte_string_chars_format::base16;
1475
                    break;
1476
                case semantic_tag::base64:
1477
                    encoding_hint = byte_string_chars_format::base64;
1478
                    break;
1479
                case semantic_tag::base64url:
1480
                    encoding_hint = byte_string_chars_format::base64url;
1481
                    break;
1482
                default:
1483
                    encoding_hint = byte_string_chars_format::none;
1484
                    break;
1485
            }
1486
1487
            byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), 
1488
                                                                                       encoding_hint, 
1489
                                                                                       byte_string_chars_format::base64url);
1490
            switch (format)
1491
            {
1492
                case byte_string_chars_format::base16:
1493
                {
1494
                    sink_.push_back('\"');
1495
                    bytes_to_base16(b.begin(),b.end(),sink_);
1496
                    sink_.push_back('\"');
1497
                    break;
1498
                }
1499
                case byte_string_chars_format::base64:
1500
                {
1501
                    sink_.push_back('\"');
1502
                    bytes_to_base64(b.begin(), b.end(), sink_);
1503
                    sink_.push_back('\"');
1504
                    break;
1505
                }
1506
                case byte_string_chars_format::base64url:
1507
                {
1508
                    sink_.push_back('\"');
1509
                    bytes_to_base64url(b.begin(),b.end(),sink_);
1510
                    sink_.push_back('\"');
1511
                    break;
1512
                }
1513
                default:
1514
                {
1515
                    JSONCONS_UNREACHABLE();
1516
                }
1517
            }
1518
1519
            if (!stack_.empty())
1520
            {
1521
                stack_.back().increment_count();
1522
            }
1523
            JSONCONS_VISITOR_RETURN;
1524
        }
1525
1526
        JSONCONS_VISITOR_RETURN_TYPE visit_double(double value, 
1527
                             semantic_tag,
1528
                             const ser_context& context,
1529
                             std::error_code& ec) final
1530
        {
1531
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1532
            {
1533
                sink_.push_back(',');
1534
            }
1535
1536
            if (JSONCONS_UNLIKELY(!std::isfinite(value)))
1537
            {
1538
                if ((std::isnan)(value))
1539
                {
1540
                    if (options_.enable_nan_to_num())
1541
                    {
1542
                        sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length());
1543
                    }
1544
                    else if (options_.enable_nan_to_str())
1545
                    {
1546
                        write_string(options_.nan_to_str(), semantic_tag::none, context, ec);
1547
                    }
1548
                    else
1549
                    {
1550
                        sink_.append(null_constant().data(), null_constant().size());
1551
                    }
1552
                }
1553
                else if (value == std::numeric_limits<double>::infinity())
1554
                {
1555
                    if (options_.enable_inf_to_num())
1556
                    {
1557
                        sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length());
1558
                    }
1559
                    else if (options_.enable_inf_to_str())
1560
                    {
1561
                        write_string(options_.inf_to_str(), semantic_tag::none, context, ec);
1562
                    }
1563
                    else
1564
                    {
1565
                        sink_.append(null_constant().data(), null_constant().size());
1566
                    }
1567
                }
1568
                else 
1569
                {
1570
                    if (options_.enable_neginf_to_num())
1571
                    {
1572
                        sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length());
1573
                    }
1574
                    else if (options_.enable_neginf_to_str())
1575
                    {
1576
                        write_string(options_.neginf_to_str(), semantic_tag::none, context, ec);
1577
                    }
1578
                    else
1579
                    {
1580
                        sink_.append(null_constant().data(), null_constant().size());
1581
                    }
1582
                }
1583
            }
1584
            else
1585
            {
1586
                fp_(value, sink_);
1587
            }
1588
1589
            if (!stack_.empty())
1590
            {
1591
                stack_.back().increment_count();
1592
            }
1593
            JSONCONS_VISITOR_RETURN;
1594
        }
1595
1596
        JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t value, 
1597
                            semantic_tag,
1598
                            const ser_context&,
1599
                            std::error_code&) final
1600
        {
1601
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1602
            {
1603
                sink_.push_back(',');
1604
            }
1605
            jsoncons::from_integer(value, sink_);
1606
            if (!stack_.empty())
1607
            {
1608
                stack_.back().increment_count();
1609
            }
1610
            JSONCONS_VISITOR_RETURN;
1611
        }
1612
1613
        JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t value, 
1614
                             semantic_tag, 
1615
                             const ser_context&,
1616
                             std::error_code&) final
1617
        {
1618
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1619
            {
1620
                sink_.push_back(',');
1621
            }
1622
            jsoncons::from_integer(value, sink_);
1623
            if (!stack_.empty())
1624
            {
1625
                stack_.back().increment_count();
1626
            }
1627
            JSONCONS_VISITOR_RETURN;
1628
        }
1629
1630
        JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) final
1631
        {
1632
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
1633
            {
1634
                sink_.push_back(',');
1635
            }
1636
1637
            if (value)
1638
            {
1639
                sink_.append(true_constant().data(), true_constant().size());
1640
            }
1641
            else
1642
            {
1643
                sink_.append(false_constant().data(), false_constant().size());
1644
            }
1645
1646
            if (!stack_.empty())
1647
            {
1648
                stack_.back().increment_count();
1649
            }
1650
            JSONCONS_VISITOR_RETURN;
1651
        }
1652
    };
1653
1654
    using json_stream_encoder = basic_json_encoder<char,jsoncons::stream_sink<char>>;
1655
    using wjson_stream_encoder = basic_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>>;
1656
    using compact_json_stream_encoder = basic_compact_json_encoder<char,jsoncons::stream_sink<char>>;
1657
    using compact_wjson_stream_encoder = basic_compact_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>>;
1658
1659
    using json_string_encoder = basic_json_encoder<char,jsoncons::string_sink<std::string>>;
1660
    using wjson_string_encoder = basic_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>>;
1661
    using compact_json_string_encoder = basic_compact_json_encoder<char,jsoncons::string_sink<std::string>>;
1662
    using compact_wjson_string_encoder = basic_compact_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>>;
1663
1664
} // namespace jsoncons
1665
1666
#endif // JSONCONS_JSON_ENCODER_HPP