Coverage Report

Created: 2026-01-09 06:53

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
0
    {
41
0
        return c <= 0x1F || c == 0x7f;
42
0
    }
43
44
    inline
45
    bool is_non_ascii_codepoint(uint32_t cp)
46
0
    {
47
0
        return cp >= 0x80;
48
0
    }
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
    {
55
        std::size_t count = 0;
56
        const CharT* begin = s;
57
        const CharT* end = s + length;
58
        for (const CharT* it = begin; it != end; ++it)
59
        {
60
            CharT c = *it;
61
            switch (c)
62
            {
63
                case '\\':
64
                    sink.push_back('\\');
65
                    sink.push_back('\\');
66
                    count += 2;
67
                    break;
68
                case '"':
69
                    sink.push_back('\\');
70
                    sink.push_back('\"');
71
                    count += 2;
72
                    break;
73
                case '\b':
74
                    sink.push_back('\\');
75
                    sink.push_back('b');
76
                    count += 2;
77
                    break;
78
                case '\f':
79
                    sink.push_back('\\');
80
                    sink.push_back('f');
81
                    count += 2;
82
                    break;
83
                case '\n':
84
                    sink.push_back('\\');
85
                    sink.push_back('n');
86
                    count += 2;
87
                    break;
88
                case '\r':
89
                    sink.push_back('\\');
90
                    sink.push_back('r');
91
                    count += 2;
92
                    break;
93
                case '\t':
94
                    sink.push_back('\\');
95
                    sink.push_back('t');
96
                    count += 2;
97
                    break;
98
                default:
99
                    if (escape_solidus && c == '/')
100
                    {
101
                        sink.push_back('\\');
102
                        sink.push_back('/');
103
                        count += 2;
104
                    }
105
                    else if (is_control_character(c) || escape_all_non_ascii)
106
                    {
107
                        // convert to codepoint
108
                        uint32_t cp;
109
                        auto r = unicode_traits::to_codepoint(it, end, cp, unicode_traits::conv_flags::strict);
110
                        if (r.ec != unicode_traits::conv_errc())
111
                        {
112
                            JSONCONS_THROW(ser_error(json_errc::illegal_codepoint));
113
                        }
114
                        it = r.ptr - 1;
115
                        if (is_non_ascii_codepoint(cp) || is_control_character(c))
116
                        {
117
                            if (cp > 0xFFFF)
118
                            {
119
                                cp -= 0x10000;
120
                                uint32_t first = (cp >> 10) + 0xD800;
121
                                uint32_t second = ((cp & 0x03FF) + 0xDC00);
122
123
                                sink.push_back('\\');
124
                                sink.push_back('u');
125
                                sink.push_back(jsoncons::to_hex_character(first >> 12 & 0x000F));
126
                                sink.push_back(jsoncons::to_hex_character(first >> 8 & 0x000F));
127
                                sink.push_back(jsoncons::to_hex_character(first >> 4 & 0x000F));
128
                                sink.push_back(jsoncons::to_hex_character(first & 0x000F));
129
                                sink.push_back('\\');
130
                                sink.push_back('u');
131
                                sink.push_back(jsoncons::to_hex_character(second >> 12 & 0x000F));
132
                                sink.push_back(jsoncons::to_hex_character(second >> 8 & 0x000F));
133
                                sink.push_back(jsoncons::to_hex_character(second >> 4 & 0x000F));
134
                                sink.push_back(jsoncons::to_hex_character(second & 0x000F));
135
                                count += 12;
136
                            }
137
                            else
138
                            {
139
                                sink.push_back('\\');
140
                                sink.push_back('u');
141
                                sink.push_back(jsoncons::to_hex_character(cp >> 12 & 0x000F));
142
                                sink.push_back(jsoncons::to_hex_character(cp >> 8 & 0x000F));
143
                                sink.push_back(jsoncons::to_hex_character(cp >> 4 & 0x000F));
144
                                sink.push_back(jsoncons::to_hex_character(cp & 0x000F));
145
                                count += 6;
146
                            }
147
                        }
148
                        else
149
                        {
150
                            sink.push_back(c);
151
                            ++count;
152
                        }
153
                    }
154
                    else
155
                    {
156
                        sink.push_back(c);
157
                        ++count;
158
                    }
159
                    break;
160
            }
161
        }
162
        return count;
163
    }
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
        {
204
            static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "null");
205
            return k;
206
        }
207
        static const jsoncons::basic_string_view<CharT> true_constant()
208
        {
209
            static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "true");
210
            return k;
211
        }
212
        static const jsoncons::basic_string_view<CharT> false_constant()
213
        {
214
            static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "false");
215
            return k;
216
        }
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
               : type_(type), split_kind_(split_lines), indent_before_(indent_once), new_line_after_(false),
257
                 begin_pos_(begin_pos), data_pos_(data_pos)
258
            {
259
            }
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
            {
269
                data_pos_ = pos;
270
            }
271
272
            std::size_t begin_pos() const
273
            {
274
                return begin_pos_;
275
            }
276
277
            std::size_t data_pos() const
278
            {
279
                return data_pos_;
280
            }
281
282
            std::size_t count() const
283
            {
284
                return count_;
285
            }
286
287
            void increment_count()
288
            {
289
                ++count_;
290
            }
291
292
            bool new_line_after() const
293
            {
294
                return new_line_after_;
295
            }
296
297
            void new_line_after(bool value) 
298
            {
299
                new_line_after_ = value;
300
            }
301
302
            bool is_object() const
303
            {
304
                return type_ == container_type::object;
305
            }
306
307
            bool is_array() const
308
            {
309
                return type_ == container_type::array;
310
            }
311
312
            line_split_kind split_kind() const
313
            {
314
                return split_kind_;
315
            }
316
317
            bool is_multi_line() const
318
            {
319
                return split_kind_ == line_split_kind::multi_line;
320
            }
321
322
            bool is_indent_once() const
323
            {
324
                return count_ == 0 ? indent_before_ : false;
325
            }
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
            : basic_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc)
354
        {
355
        }
356
357
        basic_json_encoder(Sink&& sink, 
358
                           const basic_json_encode_options<CharT>& options, 
359
                           const Allocator& alloc = Allocator())
360
           : sink_(std::forward<Sink>(sink)), 
361
             options_(options),
362
             indent_char_(options.indent_char()),
363
             fp_(options.float_format(), options.precision()),
364
             stack_(alloc)
365
        {
366
            switch (options.spaces_around_colon())
367
            {
368
                case spaces_option::space_after:
369
                    colon_str_ = jsoncons::basic_string_view<CharT>(colon_space.data(), colon_space.size());
370
                    break;
371
                case spaces_option::space_before:
372
                    colon_str_ = jsoncons::basic_string_view<CharT>(space_colon.data(), space_colon.size());
373
                    break;
374
                case spaces_option::space_before_and_after:
375
                    colon_str_ = jsoncons::basic_string_view<CharT>(space_colon_space.data(), space_colon_space.size());
376
                    break;
377
                default:
378
                    colon_str_ = jsoncons::basic_string_view<CharT>(colon.data(), colon.size());
379
                    break;
380
            }
381
            switch (options.spaces_around_comma())
382
            {
383
                case spaces_option::space_after:
384
                    comma_str_ = jsoncons::basic_string_view<CharT>(comma_space.data(), colon_space.size());
385
                    break;
386
                case spaces_option::space_before:
387
                    comma_str_ = jsoncons::basic_string_view<CharT>(space_comma.data(), space_comma.size());
388
                    break;
389
                case spaces_option::space_before_and_after:
390
                    comma_str_ = jsoncons::basic_string_view<CharT>(space_comma_space.data(), space_comma_space.size());
391
                    break;
392
                default:
393
                    comma_str_ = jsoncons::basic_string_view<CharT>(comma.data(), comma.size());
394
                    break;
395
            }
396
            if (options.pad_inside_object_braces())
397
            {
398
                open_brace_str_ = jsoncons::basic_string_view<CharT>(left_brace_space.data(), left_brace_space.size());
399
                close_brace_str_ = jsoncons::basic_string_view<CharT>(space_right_brace.data(), space_right_brace.size());
400
            }
401
            else
402
            {
403
                open_brace_str_ = jsoncons::basic_string_view<CharT>(left_brace.data(), left_brace.size());
404
                close_brace_str_ = jsoncons::basic_string_view<CharT>(right_brace.data(), right_brace.size());
405
            }
406
            if (options.pad_inside_array_brackets())
407
            {
408
                open_bracket_str_ = jsoncons::basic_string_view<CharT>(left_bracket_space.data(), left_bracket_space.size());
409
                close_bracket_str_ = jsoncons::basic_string_view<CharT>(space_right_bracket.data(), space_right_bracket.size());
410
            }
411
            else
412
            {
413
                open_bracket_str_ = jsoncons::basic_string_view<CharT>(left_bracket.data(), left_bracket.size());
414
                close_bracket_str_ = jsoncons::basic_string_view<CharT>(right_bracket.data(), right_bracket.size());
415
            }
416
        }
417
418
        ~basic_json_encoder() noexcept
419
        {
420
            JSONCONS_TRY
421
            {
422
                sink_.flush();
423
            }
424
            JSONCONS_CATCH(...)
425
            {
426
            }
427
        }
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
        {
450
            sink_.flush();
451
        }
452
453
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) final
454
        {
455
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
456
            {
457
                ec = json_errc::max_nesting_depth_exceeded;
458
                JSONCONS_VISITOR_RETURN;
459
            } 
460
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
461
            {
462
                sink_.append(comma_str_.data(),comma_str_.length());
463
                column_ += comma_str_.length();
464
            }
465
466
            if (!stack_.empty()) // object or array
467
            {
468
                if (stack_.back().is_object())
469
                {
470
                    line_split_kind split_kind = static_cast<uint8_t>(options_.object_object_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
471
                        options_.object_object_line_splits() : stack_.back().split_kind();
472
                    switch (split_kind)
473
                    {
474
                        case line_split_kind::same_line:
475
                        case line_split_kind::new_line:
476
                            if (column_ >= options_.line_length_limit())
477
                            {
478
                                break_line();
479
                            }
480
                            break;
481
                        default: // multi_line
482
                            break;
483
                    }
484
                    stack_.emplace_back(container_type::object,split_kind, false,
485
                                        column_, column_+open_brace_str_.length());
486
                }
487
                else // array
488
                {
489
                    line_split_kind split_kind = static_cast<uint8_t>(options_.array_object_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
490
                        options_.array_object_line_splits() : stack_.back().split_kind();
491
                    switch (split_kind)
492
                    {
493
                        case line_split_kind::same_line:
494
                            if (column_ >= options_.line_length_limit())
495
                            {
496
                                //stack_.back().new_line_after(true);
497
                                new_line();
498
                            }
499
                            else
500
                            {
501
                                stack_.back().new_line_after(true);
502
                                new_line();
503
                            }
504
                            break;
505
                        case line_split_kind::new_line:
506
                            stack_.back().new_line_after(true);
507
                            new_line();
508
                            break;
509
                        default: // multi_line
510
                            stack_.back().new_line_after(true);
511
                            new_line();
512
                            break;
513
                    }
514
                    stack_.emplace_back(container_type::object,split_kind, false,
515
                                        column_, column_+open_brace_str_.length());
516
                }
517
            }
518
            else 
519
            {
520
                stack_.emplace_back(container_type::object, options_.root_line_splits(), false,
521
                                    column_, column_+open_brace_str_.length());
522
            }
523
            indent();
524
            
525
            sink_.append(open_brace_str_.data(), open_brace_str_.length());
526
            column_ += open_brace_str_.length();
527
            JSONCONS_VISITOR_RETURN;
528
        }
529
530
        JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code&) final
531
        {
532
            JSONCONS_ASSERT(!stack_.empty());
533
            --nesting_depth_;
534
535
            unindent();
536
            if (stack_.back().new_line_after())
537
            {
538
                new_line();
539
            }
540
            stack_.pop_back();
541
            sink_.append(close_brace_str_.data(), close_brace_str_.length());
542
            column_ += close_brace_str_.length();
543
544
            end_value();
545
            JSONCONS_VISITOR_RETURN;
546
        }
547
548
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) final
549
        {
550
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
551
            {
552
                ec = json_errc::max_nesting_depth_exceeded;
553
                JSONCONS_VISITOR_RETURN;
554
            } 
555
            if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
556
            {
557
                sink_.append(comma_str_.data(),comma_str_.length());
558
                column_ += comma_str_.length();
559
            }
560
            if (!stack_.empty())
561
            {
562
                if (stack_.back().is_object())
563
                {
564
                    line_split_kind split_kind = static_cast<uint8_t>(options_.object_array_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
565
                        options_.object_array_line_splits() : 
566
                        stack_.back().split_kind();
567
                    switch (split_kind)
568
                    {
569
                        case line_split_kind::same_line:
570
                            stack_.emplace_back(container_type::array,split_kind,false,
571
                                                column_, column_ + open_bracket_str_.length());
572
                            break;
573
                        case line_split_kind::new_line:
574
                        {
575
                            stack_.emplace_back(container_type::array,split_kind,true,
576
                                                column_, column_+open_bracket_str_.length());
577
                            break;
578
                        }
579
                        default: // multi_line
580
                            stack_.emplace_back(container_type::array,split_kind,true,
581
                                                column_, column_+open_bracket_str_.length());
582
                            break;
583
                    }
584
                }
585
                else // array
586
                {
587
                    line_split_kind split_kind = static_cast<uint8_t>(options_.array_array_line_splits()) >= static_cast<uint8_t>(stack_.back().split_kind()) ? 
588
                        options_.array_array_line_splits() : stack_.back().split_kind();
589
                    switch (split_kind)
590
                    {
591
                        case line_split_kind::same_line:
592
                            if (stack_.back().is_multi_line())
593
                            {
594
                                stack_.back().new_line_after(true);
595
                                new_line();
596
                            }
597
                            stack_.emplace_back(container_type::array,split_kind, false,
598
                                                column_, column_+open_bracket_str_.length());
599
                            break;
600
                        case line_split_kind::new_line:
601
                            stack_.back().new_line_after(true);
602
                            new_line();
603
                            stack_.emplace_back(container_type::array,split_kind, true,
604
                                                column_, column_+open_bracket_str_.length());
605
                            break;
606
                        default: // multi_line
607
                            stack_.back().new_line_after(true);
608
                            new_line();
609
                            stack_.emplace_back(container_type::array,split_kind, false,
610
                                                column_, column_+open_bracket_str_.length());
611
                            break;
612
                    }
613
                }
614
            }
615
            else 
616
            {
617
                stack_.emplace_back(container_type::array, options_.root_line_splits(), false,
618
                                    column_, column_+open_bracket_str_.length());
619
            }
620
            indent();
621
            sink_.append(open_bracket_str_.data(), open_bracket_str_.length());
622
            column_ += open_bracket_str_.length();
623
            JSONCONS_VISITOR_RETURN;
624
        }
625
626
        JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code&) final
627
        {
628
            JSONCONS_ASSERT(!stack_.empty());
629
            --nesting_depth_;
630
631
            unindent();
632
            if (stack_.back().new_line_after())
633
            {
634
                new_line();
635
            }
636
            stack_.pop_back();
637
            sink_.append(close_bracket_str_.data(), close_bracket_str_.length());
638
            column_ += close_bracket_str_.length();
639
            end_value();
640
            JSONCONS_VISITOR_RETURN;
641
        }
642
643
        JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context&, std::error_code&) final
644
        {
645
            JSONCONS_ASSERT(!stack_.empty());
646
            if (stack_.back().count() > 0)
647
            {
648
                sink_.append(comma_str_.data(),comma_str_.length());
649
                column_ += comma_str_.length();
650
            }
651
652
            if (stack_.back().is_multi_line())
653
            {
654
                stack_.back().new_line_after(true);
655
                new_line();
656
            }
657
            else if (stack_.back().count() > 0 && column_ >= options_.line_length_limit())
658
            {
659
                //stack_.back().new_line_after(true);
660
                new_line(stack_.back().data_pos());
661
            }
662
663
            if (stack_.back().count() == 0)
664
            {
665
                stack_.back().set_position(column_);
666
            }
667
            sink_.push_back('\"');
668
            std::size_t length = jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
669
            sink_.push_back('\"');
670
            sink_.append(colon_str_.data(),colon_str_.length());
671
            column_ += (length+2+colon_str_.length());
672
            JSONCONS_VISITOR_RETURN;
673
        }
674
675
        JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final
676
        {
677
            if (!stack_.empty()) 
678
            {
679
                if (stack_.back().is_array())
680
                {
681
                    begin_scalar_value();
682
                }
683
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
684
                {
685
                    break_line();
686
                }
687
            }
688
689
            sink_.append(null_constant().data(), null_constant().size());
690
            column_ += null_constant().size();
691
692
            end_value();
693
            JSONCONS_VISITOR_RETURN;
694
        }
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
        {
698
            if (!stack_.empty()) 
699
            {
700
                if (stack_.back().is_array())
701
                {
702
                    begin_scalar_value();
703
                }
704
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
705
                {
706
                    break_line();
707
                }
708
            }
709
            
710
            write_string(sv, tag, context, ec);
711
712
            end_value();
713
            JSONCONS_VISITOR_RETURN;
714
        }
715
716
        void write_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) 
717
        {
718
            if (JSONCONS_LIKELY(tag == semantic_tag::noesc && !options_.escape_all_non_ascii() && !options_.escape_solidus()))
719
            {
720
                //std::cout << "noesc\n";
721
                sink_.push_back('\"');
722
                const CharT* begin = sv.data();
723
                const CharT* end = begin + sv.length();
724
                for (const CharT* it = begin; it != end; ++it)
725
                {
726
                    sink_.push_back(*it);
727
                }
728
                sink_.push_back('\"');
729
                column_ += (sv.length()+2);
730
            }
731
            else if (tag == semantic_tag::bigint)
732
            {
733
                write_bignum_value(sv);
734
            }
735
            else if (tag == semantic_tag::bigdec && options_.bignum_format() == bignum_format_kind::raw)
736
            {
737
                write_bignum_value(sv);
738
            }
739
            else
740
            {
741
                //if (tag != semantic_tag::bigdec)
742
                //    std::cout << "esc\n";
743
                sink_.push_back('\"');
744
                std::size_t length = jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
745
                sink_.push_back('\"');
746
                column_ += (length+2);
747
            }           
748
        }
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
        {
755
            if (!stack_.empty()) 
756
            {
757
                if (stack_.back().is_array())
758
                {
759
                    begin_scalar_value();
760
                }
761
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
762
                {
763
                    break_line();
764
                }
765
            }
766
767
            byte_string_chars_format encoding_hint;
768
            switch (tag)
769
            {
770
                case semantic_tag::base16:
771
                    encoding_hint = byte_string_chars_format::base16;
772
                    break;
773
                case semantic_tag::base64:
774
                    encoding_hint = byte_string_chars_format::base64;
775
                    break;
776
                case semantic_tag::base64url:
777
                    encoding_hint = byte_string_chars_format::base64url;
778
                    break;
779
                default:
780
                    encoding_hint = byte_string_chars_format::none;
781
                    break;
782
            }
783
784
            byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(), 
785
                                                                                                 encoding_hint, 
786
                                                                                                 byte_string_chars_format::base64url);
787
            switch (format)
788
            {
789
                case byte_string_chars_format::base16:
790
                {
791
                    sink_.push_back('\"');
792
                    std::size_t length = bytes_to_base16(b.begin(),b.end(),sink_);
793
                    sink_.push_back('\"');
794
                    column_ += (length + 2);
795
                    break;
796
                }
797
                case byte_string_chars_format::base64:
798
                {
799
                    sink_.push_back('\"');
800
                    std::size_t length = bytes_to_base64(b.begin(), b.end(), sink_);
801
                    sink_.push_back('\"');
802
                    column_ += (length + 2);
803
                    break;
804
                }
805
                case byte_string_chars_format::base64url:
806
                {
807
                    sink_.push_back('\"');
808
                    std::size_t length = bytes_to_base64url(b.begin(),b.end(),sink_);
809
                    sink_.push_back('\"');
810
                    column_ += (length + 2);
811
                    break;
812
                }
813
                default:
814
                {
815
                    JSONCONS_UNREACHABLE();
816
                }
817
            }
818
819
            end_value();
820
            JSONCONS_VISITOR_RETURN;
821
        }
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
        {
828
            if (!stack_.empty()) 
829
            {
830
                if (stack_.back().is_array())
831
                {
832
                    begin_scalar_value();
833
                }
834
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
835
                {
836
                    break_line();
837
                }
838
            }
839
840
            if (!std::isfinite(value))
841
            {
842
                if ((std::isnan)(value))
843
                {
844
                    if (options_.enable_nan_to_num())
845
                    {
846
                        sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length());
847
                        column_ += options_.nan_to_num().length();
848
                    }
849
                    else if (options_.enable_nan_to_str())
850
                    {
851
                        write_string(options_.nan_to_str(), semantic_tag::none, context, ec);
852
                    }
853
                    else
854
                    {
855
                        sink_.append(null_constant().data(), null_constant().size());
856
                        column_ += null_constant().size();
857
                    }
858
                }
859
                else if (value == std::numeric_limits<double>::infinity())
860
                {
861
                    if (options_.enable_inf_to_num())
862
                    {
863
                        sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length());
864
                        column_ += options_.inf_to_num().length();
865
                    }
866
                    else if (options_.enable_inf_to_str())
867
                    {
868
                        write_string(options_.inf_to_str(), semantic_tag::none, context, ec);
869
                    }
870
                    else
871
                    {
872
                        sink_.append(null_constant().data(), null_constant().size());
873
                        column_ += null_constant().size();
874
                    }
875
                }
876
                else
877
                {
878
                    if (options_.enable_neginf_to_num())
879
                    {
880
                        sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length());
881
                        column_ += options_.neginf_to_num().length();
882
                    }
883
                    else if (options_.enable_neginf_to_str())
884
                    {
885
                        write_string(options_.neginf_to_str(), semantic_tag::none, context, ec);
886
                    }
887
                    else
888
                    {
889
                        sink_.append(null_constant().data(), null_constant().size());
890
                        column_ += null_constant().size();
891
                    }
892
                }
893
            }
894
            else
895
            {
896
                std::size_t length = fp_(value, sink_);
897
                column_ += length;
898
            }
899
900
            end_value();
901
            JSONCONS_VISITOR_RETURN;
902
        }
903
904
        JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t value, 
905
                            semantic_tag,
906
                            const ser_context&,
907
                            std::error_code&) final
908
        {
909
            if (!stack_.empty()) 
910
            {
911
                if (stack_.back().is_array())
912
                {
913
                    begin_scalar_value();
914
                }
915
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
916
                {
917
                    break_line();
918
                }
919
            }
920
            std::size_t length = jsoncons::from_integer(value, sink_);
921
            column_ += length;
922
            end_value();
923
            JSONCONS_VISITOR_RETURN;
924
        }
925
926
        JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t value, 
927
                             semantic_tag, 
928
                             const ser_context&,
929
                             std::error_code&) final
930
        {
931
            if (!stack_.empty()) 
932
            {
933
                if (stack_.back().is_array())
934
                {
935
                    begin_scalar_value();
936
                }
937
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
938
                {
939
                    break_line();
940
                }
941
            }
942
            std::size_t length = jsoncons::from_integer(value, sink_);
943
            column_ += length;
944
            end_value();
945
            JSONCONS_VISITOR_RETURN;
946
        }
947
948
        JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) final
949
        {
950
            if (!stack_.empty()) 
951
            {
952
                if (stack_.back().is_array())
953
                {
954
                    begin_scalar_value();
955
                }
956
                if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
957
                {
958
                    break_line();
959
                }
960
            }
961
962
            if (value)
963
            {
964
                sink_.append(true_constant().data(), true_constant().size());
965
                column_ += true_constant().size();
966
            }
967
            else
968
            {
969
                sink_.append(false_constant().data(), false_constant().size());
970
                column_ += false_constant().size();
971
            }
972
973
            end_value();
974
            JSONCONS_VISITOR_RETURN;
975
        }
976
977
        void begin_scalar_value()
978
        {
979
            if (!stack_.empty())
980
            {
981
                if (stack_.back().count() > 0)
982
                {
983
                    sink_.append(comma_str_.data(),comma_str_.length());
984
                    column_ += comma_str_.length();
985
                }
986
                if (stack_.back().is_multi_line() || stack_.back().is_indent_once())
987
                {
988
                    stack_.back().new_line_after(true);
989
                    new_line();
990
                }
991
            }
992
        }
993
994
        void write_bignum_value(const string_view_type& sv)
995
        {
996
            switch (options_.bignum_format())
997
            {
998
                case bignum_format_kind::raw:
999
                {
1000
                    sink_.append(sv.data(),sv.size());
1001
                    column_ += sv.size();
1002
                    break;
1003
                }
1004
                case bignum_format_kind::base64:
1005
                {
1006
                    bigint n(sv.data(), sv.length());
1007
                    bool is_neg = n < 0;
1008
                    if (is_neg)
1009
                    {
1010
                        n = - n -1;
1011
                    }
1012
                    int signum;
1013
                    std::vector<uint8_t> v;
1014
                    n.write_bytes_be(signum, v);
1015
1016
                    sink_.push_back('\"');
1017
                    if (is_neg)
1018
                    {
1019
                        sink_.push_back('~');
1020
                        ++column_;
1021
                    }
1022
                    std::size_t length = bytes_to_base64(v.begin(), v.end(), sink_);
1023
                    sink_.push_back('\"');
1024
                    column_ += (length+2);
1025
                    break;
1026
                }
1027
                case bignum_format_kind::base64url:
1028
                {
1029
                    bigint n(sv.data(), sv.length());
1030
                    bool is_neg = n < 0;
1031
                    if (is_neg)
1032
                    {
1033
                        n = - n -1;
1034
                    }
1035
                    int signum;
1036
                    std::vector<uint8_t> v;
1037
                    n.write_bytes_be(signum, v);
1038
1039
                    sink_.push_back('\"');
1040
                    if (is_neg)
1041
                    {
1042
                        sink_.push_back('~');
1043
                        ++column_;
1044
                    }
1045
                    std::size_t length = bytes_to_base64url(v.begin(), v.end(), sink_);
1046
                    sink_.push_back('\"');
1047
                    column_ += (length+2);
1048
                    break;
1049
                }
1050
                default:
1051
                {
1052
                    sink_.push_back('\"');
1053
                    sink_.append(sv.data(),sv.size());
1054
                    sink_.push_back('\"');
1055
                    column_ += (sv.size() + 2);
1056
                    break;
1057
                }
1058
            }
1059
        }
1060
1061
        void end_value()
1062
        {
1063
            if (!stack_.empty())
1064
            {
1065
                stack_.back().increment_count();
1066
            }
1067
        }
1068
1069
        void indent()
1070
        {
1071
            indent_amount_ += static_cast<uint8_t>(options_.indent_size());
1072
        }
1073
1074
        void unindent()
1075
        {
1076
            indent_amount_ -= static_cast<uint8_t>(options_.indent_size());
1077
        }
1078
1079
        void new_line()
1080
        {
1081
            sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length());
1082
            for (int i = 0; i < indent_amount_; ++i)
1083
            {
1084
                sink_.push_back(indent_char_);
1085
            }
1086
            column_ = indent_amount_;
1087
        }
1088
1089
        void new_line(std::size_t len)
1090
        {
1091
            sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length());
1092
            for (std::size_t i = 0; i < len; ++i)
1093
            {
1094
                sink_.push_back(' ');
1095
            }
1096
            column_ = len;
1097
        }
1098
1099
        void break_line()
1100
        {
1101
            stack_.back().new_line_after(true);
1102
            new_line();
1103
        }
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