Coverage Report

Created: 2025-10-10 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons_ext/msgpack/msgpack_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_EXT_MSGPACK_MSGPACK_ENCODER_HPP
8
#define JSONCONS_EXT_MSGPACK_MSGPACK_ENCODER_HPP
9
10
#include <cstddef>
11
#include <cstdint>
12
#include <cstdlib>
13
#include <limits> // std::numeric_limits
14
#include <memory>
15
#include <system_error>
16
#include <utility> // std::move
17
#include <vector>
18
19
#include <jsoncons/config/compiler_support.hpp>
20
#include <jsoncons/config/jsoncons_config.hpp>
21
#include <jsoncons/utility/read_number.hpp>
22
#include <jsoncons/json_exception.hpp>
23
#include <jsoncons/json_type.hpp>
24
#include <jsoncons/json_visitor.hpp>
25
#include <jsoncons/semantic_tag.hpp>
26
#include <jsoncons/ser_util.hpp>
27
#include <jsoncons/sink.hpp>
28
#include <jsoncons/utility/bigint.hpp>
29
#include <jsoncons/utility/binary.hpp>
30
#include <jsoncons/utility/byte_string.hpp>
31
#include <jsoncons/utility/unicode_traits.hpp>
32
33
#include <jsoncons_ext/msgpack/msgpack_error.hpp>
34
#include <jsoncons_ext/msgpack/msgpack_options.hpp>
35
#include <jsoncons_ext/msgpack/msgpack_type.hpp>
36
37
namespace jsoncons { 
38
namespace msgpack {
39
40
    enum class msgpack_container_type {object, array};
41
42
    template <typename Sink=jsoncons::binary_stream_sink,typename Allocator=std::allocator<char>>
43
    class basic_msgpack_encoder final : public basic_json_visitor<char>
44
    {
45
        enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 };
46
47
        static constexpr int64_t nanos_in_milli = 1000000;
48
        static constexpr int64_t nanos_in_second = 1000000000;
49
        static constexpr int64_t millis_in_second = 1000;
50
    public:
51
        using allocator_type = Allocator;
52
        using char_type = char;
53
        using typename basic_json_visitor<char>::string_view_type;
54
        using sink_type = Sink;
55
56
    private:
57
        struct stack_item
58
        {
59
            msgpack_container_type type_;
60
            std::size_t length_;
61
            std::size_t index_{0};
62
63
            stack_item(msgpack_container_type type, std::size_t length = 0) noexcept
64
104k
               : type_(type), length_(length)
65
104k
            {
66
104k
            }
67
68
            std::size_t length() const
69
164k
            {
70
164k
                return length_;
71
164k
            }
72
73
            std::size_t count() const
74
164k
            {
75
164k
                return is_object() ? index_/2 : index_;
76
164k
            }
77
78
            bool is_object() const
79
164k
            {
80
164k
                return type_ == msgpack_container_type::object;
81
164k
            }
82
        };
83
84
        Sink sink_;
85
        const msgpack_encode_options options_;
86
        allocator_type alloc_;
87
88
        std::vector<stack_item> stack_;
89
        int nesting_depth_{0};
90
    public:
91
92
        // Noncopyable and nonmoveable
93
        basic_msgpack_encoder(const basic_msgpack_encoder&) = delete;
94
        basic_msgpack_encoder(basic_msgpack_encoder&&) = delete;
95
96
        explicit basic_msgpack_encoder(Sink&& sink, const Allocator& alloc = Allocator())
97
6.00k
           : basic_msgpack_encoder(std::forward<Sink>(sink), msgpack_encode_options(), alloc)
98
6.00k
        {
99
6.00k
        }
100
101
        explicit basic_msgpack_encoder(Sink&& sink, 
102
            const msgpack_encode_options& options, 
103
            const Allocator& alloc = Allocator())
104
6.00k
           : sink_(std::forward<Sink>(sink)),
105
6.00k
             options_(options),
106
6.00k
             alloc_(alloc)
107
6.00k
        {
108
6.00k
        }
109
110
        ~basic_msgpack_encoder() noexcept
111
6.00k
        {
112
6.00k
            sink_.flush();
113
6.00k
        }
114
115
        basic_msgpack_encoder& operator=(const basic_msgpack_encoder&) = delete;
116
        basic_msgpack_encoder& operator=(basic_msgpack_encoder&&) = delete;
117
118
        void reset()
119
        {
120
            stack_.clear();
121
            nesting_depth_ = 0;
122
        }
123
124
        void reset(Sink&& sink)
125
        {
126
            sink_ = std::move(sink);
127
            reset();
128
        }
129
130
    private:
131
        // Implementing methods
132
133
        void visit_flush() final
134
1.38k
        {
135
1.38k
            sink_.flush();
136
1.38k
        }
137
138
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) final
139
0
        {
140
0
            ec = msgpack_errc::object_length_required;
141
0
            JSONCONS_VISITOR_RETURN;
142
0
        }
143
144
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) final
145
44.2k
        {
146
44.2k
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
147
0
            {
148
0
                ec = msgpack_errc::max_nesting_depth_exceeded;
149
0
                JSONCONS_VISITOR_RETURN;
150
0
            } 
151
44.2k
            stack_.emplace_back(msgpack_container_type::object, length);
152
153
44.2k
            if (length <= 15)
154
42.4k
            {
155
                // fixmap
156
42.4k
                sink_.push_back(jsoncons::msgpack::msgpack_type::fixmap_base_type | (length & 0xf));
157
42.4k
            }
158
1.77k
            else if (length <= 65535)
159
740
            {
160
                // map 16
161
740
                sink_.push_back(jsoncons::msgpack::msgpack_type::map16_type);
162
740
                binary::native_to_big(static_cast<uint16_t>(length), 
163
740
                                      std::back_inserter(sink_));
164
740
            }
165
1.03k
            else if (length <= (std::numeric_limits<uint32_t>::max)())
166
1.03k
            {
167
                // map 32
168
1.03k
                sink_.push_back(jsoncons::msgpack::msgpack_type::map32_type);
169
1.03k
                binary::native_to_big(static_cast<uint32_t>(length),
170
1.03k
                                      std::back_inserter(sink_));
171
1.03k
            }
172
173
44.2k
            JSONCONS_VISITOR_RETURN;
174
44.2k
        }
175
176
        JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code& ec) final
177
36.6k
        {
178
36.6k
            JSONCONS_ASSERT(!stack_.empty());
179
36.6k
            --nesting_depth_;
180
181
36.6k
            if (stack_.back().count() < stack_.back().length())
182
425
            {
183
425
                ec = msgpack_errc::too_few_items;
184
425
                JSONCONS_VISITOR_RETURN;
185
425
            }
186
36.2k
            else if (stack_.back().count() > stack_.back().length())
187
0
            {
188
0
                ec = msgpack_errc::too_many_items;
189
0
                JSONCONS_VISITOR_RETURN;
190
0
            }
191
192
36.2k
            stack_.pop_back();
193
36.2k
            end_value();
194
36.2k
            JSONCONS_VISITOR_RETURN;
195
36.6k
        }
196
197
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) final
198
0
        {
199
0
            ec = msgpack_errc::array_length_required;
200
0
            JSONCONS_VISITOR_RETURN;
201
0
        }
202
203
        JSONCONS_VISITOR_RETURN_TYPE visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) final
204
60.0k
        {
205
60.0k
            if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
206
0
            {
207
0
                ec = msgpack_errc::max_nesting_depth_exceeded;
208
0
                JSONCONS_VISITOR_RETURN;
209
0
            } 
210
60.0k
            stack_.emplace_back(msgpack_container_type::array, length);
211
60.0k
            if (length <= 15)
212
55.8k
            {
213
                // fixarray
214
55.8k
                sink_.push_back(jsoncons::msgpack::msgpack_type::fixarray_base_type | (length & 0xf));
215
55.8k
            }
216
4.11k
            else if (length <= (std::numeric_limits<uint16_t>::max)())
217
1.94k
            {
218
                // array 16
219
1.94k
                sink_.push_back(jsoncons::msgpack::msgpack_type::array16_type);
220
1.94k
                binary::native_to_big(static_cast<uint16_t>(length),std::back_inserter(sink_));
221
1.94k
            }
222
2.17k
            else if (length <= (std::numeric_limits<uint32_t>::max)())
223
2.17k
            {
224
                // array 32
225
2.17k
                sink_.push_back(jsoncons::msgpack::msgpack_type::array32_type);
226
2.17k
                binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
227
2.17k
            }
228
60.0k
            JSONCONS_VISITOR_RETURN;
229
60.0k
        }
230
231
        JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code& ec) final
232
46.1k
        {
233
46.1k
            JSONCONS_ASSERT(!stack_.empty());
234
235
46.1k
            --nesting_depth_;
236
237
46.1k
            if (stack_.back().count() < stack_.back().length())
238
508
            {
239
508
                ec = msgpack_errc::too_few_items;
240
508
                JSONCONS_VISITOR_RETURN;
241
508
            }
242
45.6k
            else if (stack_.back().count() > stack_.back().length())
243
0
            {
244
0
                ec = msgpack_errc::too_many_items;
245
0
                JSONCONS_VISITOR_RETURN;
246
0
            }
247
248
45.6k
            stack_.pop_back();
249
45.6k
            end_value();
250
45.6k
            JSONCONS_VISITOR_RETURN;
251
46.1k
        }
252
253
        JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context& context, std::error_code& ec) override
254
206k
        {
255
206k
            visit_string(name, semantic_tag::none, context, ec);
256
206k
            JSONCONS_VISITOR_RETURN;
257
206k
        }
258
259
        JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final
260
3.83k
        {
261
            // nil
262
3.83k
            sink_.push_back(jsoncons::msgpack::msgpack_type::nil_type);
263
3.83k
            end_value();
264
3.83k
            JSONCONS_VISITOR_RETURN;
265
3.83k
        }
266
267
        void write_timestamp(int64_t seconds, int64_t nanoseconds)
268
10.3k
        {
269
10.3k
            if ((seconds >> 34) == 0) 
270
4.66k
            {
271
4.66k
                uint64_t data64 = (nanoseconds << 34) | seconds;
272
4.66k
                if ((data64 & 0xffffffff00000000L) == 0) 
273
2.10k
                {
274
                    // timestamp 32
275
2.10k
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type);
276
2.10k
                    sink_.push_back(0xff);
277
2.10k
                    binary::native_to_big(static_cast<uint32_t>(data64), std::back_inserter(sink_));
278
2.10k
                }
279
2.56k
                else 
280
2.56k
                {
281
                    // timestamp 64
282
2.56k
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type);
283
2.56k
                    sink_.push_back(0xff);
284
2.56k
                    binary::native_to_big(static_cast<uint64_t>(data64), std::back_inserter(sink_));
285
2.56k
                }
286
4.66k
            }
287
5.66k
            else 
288
5.66k
            {
289
                // timestamp 96
290
5.66k
                sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type);
291
5.66k
                sink_.push_back(0x0c); // 12
292
5.66k
                sink_.push_back(0xff);
293
5.66k
                binary::native_to_big(static_cast<uint32_t>(nanoseconds), std::back_inserter(sink_));
294
5.66k
                binary::native_to_big(static_cast<uint64_t>(seconds), std::back_inserter(sink_));
295
5.66k
            }
296
10.3k
        }
297
298
        JSONCONS_VISITOR_RETURN_TYPE visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) final
299
217k
        {
300
217k
            switch (tag)
301
217k
            {
302
0
                case semantic_tag::epoch_second:
303
0
                {
304
0
                    int64_t seconds;
305
0
                    auto result = jsoncons::utility::to_integer(sv.data(), sv.length(), seconds);
306
0
                    if (!result)
307
0
                    {
308
0
                        ec = msgpack_errc::invalid_timestamp;
309
0
                        JSONCONS_VISITOR_RETURN;
310
0
                    }
311
0
                    write_timestamp(seconds, 0);
312
0
                    break;
313
0
                }
314
0
                case semantic_tag::epoch_milli:
315
0
                {
316
0
                    bigint n;
317
0
                    auto result = to_bigint(sv.data(), sv.length(), n);
318
0
                    if (!result)
319
0
                    {
320
0
                        ec = msgpack_errc::invalid_timestamp;
321
0
                        JSONCONS_VISITOR_RETURN;
322
0
                    }
323
0
                    if (n != 0)
324
0
                    {
325
0
                        bigint q;
326
0
                        bigint rem;
327
0
                        n.divide(millis_in_second, q, rem, true);
328
0
                        auto seconds = static_cast<int64_t>(q);
329
0
                        auto nanoseconds = static_cast<int64_t>(rem) * nanos_in_milli;
330
0
                        if (nanoseconds < 0)
331
0
                        {
332
0
                            nanoseconds = -nanoseconds; 
333
0
                        }
334
0
                        write_timestamp(seconds, nanoseconds);
335
0
                    }
336
0
                    else
337
0
                    {
338
0
                        write_timestamp(0, 0);
339
0
                    }
340
0
                    break;
341
0
                }
342
9.04k
                case semantic_tag::epoch_nano:
343
9.04k
                {
344
9.04k
                    bigint n;
345
9.04k
                    auto result = to_bigint(sv.data(), sv.length(), n);
346
9.04k
                    if (!result)
347
0
                    {
348
0
                        ec = msgpack_errc::invalid_timestamp;
349
0
                        JSONCONS_VISITOR_RETURN;
350
0
                    }
351
9.04k
                    if (n != 0)
352
8.35k
                    {
353
8.35k
                        bigint q;
354
8.35k
                        bigint rem;
355
8.35k
                        n.divide(nanos_in_second, q, rem, true);
356
8.35k
                        auto seconds = static_cast<int64_t>(q);
357
8.35k
                        auto nanoseconds = static_cast<int64_t>(rem);
358
8.35k
                        if (nanoseconds < 0)
359
2.47k
                        {
360
2.47k
                            nanoseconds = -nanoseconds; 
361
2.47k
                        }
362
8.35k
                        write_timestamp(seconds, nanoseconds);
363
8.35k
                    }
364
691
                    else
365
691
                    {
366
691
                        write_timestamp(0, 0);
367
691
                    }
368
9.04k
                    break;
369
9.04k
                }
370
208k
                default:
371
208k
                {
372
208k
                    write_string_value(sv);
373
208k
                    end_value();
374
208k
                    break;
375
9.04k
                }
376
217k
            }
377
217k
            JSONCONS_VISITOR_RETURN;
378
217k
        }
379
380
        void write_string_value(const string_view_type& sv) 
381
208k
        {
382
208k
            auto sink = unicode_traits::validate(sv.data(), sv.size());
383
208k
            if (sink.ec != unicode_traits::conv_errc())
384
0
            {
385
0
                JSONCONS_THROW(ser_error(msgpack_errc::invalid_utf8_text_string));
386
0
            }
387
388
208k
            const size_t length = sv.length();
389
208k
            if (length <= 31)
390
207k
            {
391
                // fixstr stores a byte array whose length is upto 31 bytes
392
207k
                sink_.push_back(jsoncons::msgpack::msgpack_type::fixstr_base_type | static_cast<uint8_t>(length));
393
207k
            }
394
1.87k
            else if (length <= (std::numeric_limits<uint8_t>::max)())
395
838
            {
396
                // str 8 stores a byte array whose length is upto (2^8)-1 bytes
397
838
                sink_.push_back(jsoncons::msgpack::msgpack_type::str8_type);
398
838
                sink_.push_back(static_cast<uint8_t>(length));
399
838
            }
400
1.03k
            else if (length <= (std::numeric_limits<uint16_t>::max)())
401
664
            {
402
                // str 16 stores a byte array whose length is upto (2^16)-1 bytes
403
664
                sink_.push_back(jsoncons::msgpack::msgpack_type::str16_type);
404
664
                binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
405
664
            }
406
371
            else if (length <= (std::numeric_limits<uint32_t>::max)())
407
371
            {
408
                // str 32 stores a byte array whose length is upto (2^32)-1 bytes
409
371
                sink_.push_back(jsoncons::msgpack::msgpack_type::str32_type);
410
371
                binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
411
371
            }
412
413
208k
            for (auto c : sv)
414
87.8M
            {
415
87.8M
                sink_.push_back(c);
416
87.8M
            }
417
208k
        }
418
419
        JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, 
420
            semantic_tag, 
421
            const ser_context&,
422
            std::error_code&) final
423
2.16k
        {
424
425
2.16k
            const std::size_t length = b.size();
426
2.16k
            if (length <= (std::numeric_limits<uint8_t>::max)())
427
1.64k
            {
428
                // bin 8 stores a byte array whose length is upto (2^8)-1 bytes
429
1.64k
                sink_.push_back(jsoncons::msgpack::msgpack_type::bin8_type);
430
1.64k
                sink_.push_back(static_cast<uint8_t>(length));
431
1.64k
            }
432
518
            else if (length <= (std::numeric_limits<uint16_t>::max)())
433
443
            {
434
                // bin 16 stores a byte array whose length is upto (2^16)-1 bytes
435
443
                sink_.push_back(jsoncons::msgpack::msgpack_type::bin16_type);
436
443
                binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
437
443
            }
438
75
            else if (length <= (std::numeric_limits<uint32_t>::max)())
439
75
            {
440
                // bin 32 stores a byte array whose length is upto (2^32)-1 bytes
441
75
                sink_.push_back(jsoncons::msgpack::msgpack_type::bin32_type);
442
75
                binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
443
75
            }
444
445
2.16k
            for (auto c : b)
446
7.61M
            {
447
7.61M
                sink_.push_back(c);
448
7.61M
            }
449
450
2.16k
            end_value();
451
2.16k
            JSONCONS_VISITOR_RETURN;
452
2.16k
        }
453
454
        JSONCONS_VISITOR_RETURN_TYPE visit_byte_string(const byte_string_view& b, 
455
            uint64_t ext_tag, 
456
            const ser_context&,
457
            std::error_code&) final
458
30.2k
        {
459
30.2k
            const std::size_t length = b.size();
460
30.2k
            switch (length)
461
30.2k
            {
462
1.43k
                case 1:
463
1.43k
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext1_type);
464
1.43k
                    sink_.push_back(static_cast<uint8_t>(ext_tag));
465
1.43k
                    break;
466
21.6k
                case 2:
467
21.6k
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext2_type);
468
21.6k
                    sink_.push_back(static_cast<uint8_t>(ext_tag));
469
21.6k
                    break;
470
2.25k
                case 4:
471
2.25k
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type);
472
2.25k
                    sink_.push_back(static_cast<uint8_t>(ext_tag));
473
2.25k
                    break;
474
911
                case 8:
475
911
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type);
476
911
                    sink_.push_back(static_cast<uint8_t>(ext_tag));
477
911
                    break;
478
2.18k
                case 16:
479
2.18k
                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext16_type);
480
2.18k
                    sink_.push_back(static_cast<uint8_t>(ext_tag));
481
2.18k
                    break;
482
1.85k
                default:
483
1.85k
                    if (length <= (std::numeric_limits<uint8_t>::max)())
484
1.38k
                    {
485
1.38k
                        sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type);
486
1.38k
                        sink_.push_back(static_cast<uint8_t>(length));
487
1.38k
                        sink_.push_back(static_cast<uint8_t>(ext_tag));
488
1.38k
                    }
489
470
                    else if (length <= (std::numeric_limits<uint16_t>::max)())
490
406
                    {
491
406
                        sink_.push_back(jsoncons::msgpack::msgpack_type::ext16_type);
492
406
                        binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
493
406
                        sink_.push_back(static_cast<uint8_t>(ext_tag));
494
406
                    }
495
64
                    else if (length <= (std::numeric_limits<uint32_t>::max)())
496
64
                    {
497
64
                        sink_.push_back(jsoncons::msgpack::msgpack_type::ext32_type);
498
64
                        binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
499
64
                        sink_.push_back(static_cast<uint8_t>(ext_tag));
500
64
                    }
501
1.85k
                    break;
502
30.2k
            }
503
504
30.2k
            for (auto c : b)
505
7.51M
            {
506
7.51M
                sink_.push_back(c);
507
7.51M
            }
508
509
30.2k
            end_value();
510
30.2k
            JSONCONS_VISITOR_RETURN;
511
30.2k
        }
512
513
        JSONCONS_VISITOR_RETURN_TYPE visit_double(double val, 
514
            semantic_tag,
515
            const ser_context&,
516
            std::error_code&) final
517
43.1k
        {
518
43.1k
            float valf = (float)val;
519
43.1k
            if ((double)valf == val)
520
37.7k
            {
521
                // float 32
522
37.7k
                sink_.push_back(jsoncons::msgpack::msgpack_type::float32_type);
523
37.7k
                binary::native_to_big(valf,std::back_inserter(sink_));
524
37.7k
            }
525
5.42k
            else
526
5.42k
            {
527
                // float 64
528
5.42k
                sink_.push_back(jsoncons::msgpack::msgpack_type::float64_type);
529
5.42k
                binary::native_to_big(val,std::back_inserter(sink_));
530
5.42k
            }
531
532
            // write double
533
534
43.1k
            end_value();
535
43.1k
            JSONCONS_VISITOR_RETURN;
536
43.1k
        }
537
538
        JSONCONS_VISITOR_RETURN_TYPE visit_int64(int64_t val, 
539
            semantic_tag tag, 
540
            const ser_context&,
541
            std::error_code&) final
542
160k
        {
543
160k
            switch (tag)
544
160k
            {
545
0
                case semantic_tag::epoch_second:
546
0
                    write_timestamp(val, 0);
547
0
                    break;
548
0
                case semantic_tag::epoch_milli:
549
0
                {
550
0
                    if (val != 0)
551
0
                    {
552
0
                        auto dv = std::div(val,millis_in_second);
553
0
                        int64_t seconds = dv.quot;
554
0
                        int64_t nanoseconds = dv.rem*nanos_in_milli;
555
0
                        if (nanoseconds < 0)
556
0
                        {
557
0
                            nanoseconds = -nanoseconds; 
558
0
                        }
559
0
                        write_timestamp(seconds, nanoseconds);
560
0
                    }
561
0
                    else
562
0
                    {
563
0
                        write_timestamp(0, 0);
564
0
                    }
565
0
                    break;
566
0
                }
567
0
                case semantic_tag::epoch_nano:
568
0
                {
569
0
                    if (val != 0)
570
0
                    {
571
0
                        auto dv = std::div(val,static_cast<int64_t>(nanos_in_second));
572
0
                        int64_t seconds = dv.quot;
573
0
                        int64_t nanoseconds = dv.rem;
574
0
                        if (nanoseconds < 0)
575
0
                        {
576
0
                            nanoseconds = -nanoseconds; 
577
0
                        }
578
0
                        write_timestamp(seconds, nanoseconds);
579
0
                    }
580
0
                    else
581
0
                    {
582
0
                        write_timestamp(0, 0);
583
0
                    }
584
0
                    break;
585
0
                }
586
160k
                default:
587
160k
                {
588
160k
                    if (val >= 0)
589
11.7k
                    {
590
11.7k
                        if (val <= 0x7f)
591
503
                        {
592
                            // positive fixnum stores 7-bit positive integer
593
503
                            sink_.push_back(static_cast<uint8_t>(val));
594
503
                        }
595
11.2k
                        else if (val <= (std::numeric_limits<uint8_t>::max)())
596
511
                        {
597
                            // uint 8 stores a 8-bit unsigned integer
598
511
                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type);
599
511
                            sink_.push_back(static_cast<uint8_t>(val));
600
511
                        }
601
10.7k
                        else if (val <= (std::numeric_limits<uint16_t>::max)())
602
553
                        {
603
                            // uint 16 stores a 16-bit big-endian unsigned integer
604
553
                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type);
605
553
                            binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_));
606
553
                        }
607
10.1k
                        else if (val <= (std::numeric_limits<uint32_t>::max)())
608
321
                        {
609
                            // uint 32 stores a 32-bit big-endian unsigned integer
610
321
                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type);
611
321
                            binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_));
612
321
                        }
613
9.85k
                        else if (val <= (std::numeric_limits<int64_t>::max)())
614
9.85k
                        {
615
                            // int 64 stores a 64-bit big-endian signed integer
616
9.85k
                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type);
617
9.85k
                            binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_));
618
9.85k
                        }
619
11.7k
                    }
620
148k
                    else
621
148k
                    {
622
148k
                        if (val >= -32)
623
86.4k
                        {
624
                            // negative fixnum stores 5-bit negative integer
625
86.4k
                            binary::native_to_big(static_cast<int8_t>(val), std::back_inserter(sink_));
626
86.4k
                        }
627
62.3k
                        else if (val >= (std::numeric_limits<int8_t>::lowest)())
628
36.8k
                        {
629
                            // int 8 stores a 8-bit signed integer
630
36.8k
                            sink_.push_back(jsoncons::msgpack::msgpack_type::int8_type);
631
36.8k
                            binary::native_to_big(static_cast<int8_t>(val),std::back_inserter(sink_));
632
36.8k
                        }
633
25.5k
                        else if (val >= (std::numeric_limits<int16_t>::lowest)())
634
14.9k
                        {
635
                            // int 16 stores a 16-bit big-endian signed integer
636
14.9k
                            sink_.push_back(jsoncons::msgpack::msgpack_type::int16_type);
637
14.9k
                            binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_));
638
14.9k
                        }
639
10.5k
                        else if (val >= (std::numeric_limits<int32_t>::lowest)())
640
6.87k
                        {
641
                            // int 32 stores a 32-bit big-endian signed integer
642
6.87k
                            sink_.push_back(jsoncons::msgpack::msgpack_type::int32_type);
643
6.87k
                            binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_));
644
6.87k
                        }
645
3.72k
                        else if (val >= (std::numeric_limits<int64_t>::lowest)())
646
3.72k
                        {
647
                            // int 64 stores a 64-bit big-endian signed integer
648
3.72k
                            sink_.push_back(jsoncons::msgpack::msgpack_type::int64_type);
649
3.72k
                            binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_));
650
3.72k
                        }
651
148k
                    }
652
160k
                }
653
160k
                break;
654
160k
            }
655
160k
            end_value();
656
160k
            JSONCONS_VISITOR_RETURN;
657
160k
        }
658
659
        JSONCONS_VISITOR_RETURN_TYPE visit_uint64(uint64_t val, 
660
            semantic_tag tag, 
661
            const ser_context&,
662
            std::error_code&) final
663
292k
        {
664
292k
            switch (tag)
665
292k
            {
666
1.28k
                case semantic_tag::epoch_second:
667
1.28k
                    write_timestamp(static_cast<int64_t>(val), 0);
668
1.28k
                    break;
669
0
                case semantic_tag::epoch_milli:
670
0
                {
671
0
                    if (val != 0)
672
0
                    {
673
0
                        auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(millis_in_second));
674
0
                        int64_t seconds = dv.quot;
675
0
                        int64_t nanoseconds = dv.rem*nanos_in_milli;
676
0
                        if (nanoseconds < 0)
677
0
                        {
678
0
                            nanoseconds = -nanoseconds; 
679
0
                        }
680
0
                        write_timestamp(seconds, nanoseconds);
681
0
                    }
682
0
                    else
683
0
                    {
684
0
                        write_timestamp(0, 0);
685
0
                    }
686
0
                    break;
687
0
                }
688
0
                case semantic_tag::epoch_nano:
689
0
                {
690
0
                    if (val != 0)
691
0
                    {
692
0
                        auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(nanos_in_second));
693
0
                        int64_t seconds = dv.quot;
694
0
                        int64_t nanoseconds = dv.rem;
695
0
                        if (nanoseconds < 0)
696
0
                        {
697
0
                            nanoseconds = -nanoseconds; 
698
0
                        }
699
0
                        write_timestamp(seconds, nanoseconds);
700
0
                    }
701
0
                    else
702
0
                    {
703
0
                        write_timestamp(0, 0);
704
0
                    }
705
0
                    break;
706
0
                }
707
291k
                default:
708
291k
                {
709
291k
                    if (val <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
710
265k
                    {
711
                        // positive fixnum stores 7-bit positive integer
712
265k
                        sink_.push_back(static_cast<uint8_t>(val));
713
265k
                    }
714
25.9k
                    else if (val <= (std::numeric_limits<uint8_t>::max)())
715
17.3k
                    {
716
                        // uint 8 stores a 8-bit unsigned integer
717
17.3k
                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type);
718
17.3k
                        sink_.push_back(static_cast<uint8_t>(val));
719
17.3k
                    }
720
8.55k
                    else if (val <= (std::numeric_limits<uint16_t>::max)())
721
757
                    {
722
                        // uint 16 stores a 16-bit big-endian unsigned integer
723
757
                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type);
724
757
                        binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_));
725
757
                    }
726
7.79k
                    else if (val <= (std::numeric_limits<uint32_t>::max)())
727
6.51k
                    {
728
                        // uint 32 stores a 32-bit big-endian unsigned integer
729
6.51k
                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type);
730
6.51k
                        binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_));
731
6.51k
                    }
732
1.28k
                    else if (val <= (std::numeric_limits<uint64_t>::max)())
733
1.28k
                    {
734
                        // uint 64 stores a 64-bit big-endian unsigned integer
735
1.28k
                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type);
736
1.28k
                        binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_));
737
1.28k
                    }
738
291k
                    break;
739
0
                }
740
292k
            }
741
292k
            end_value();
742
292k
            JSONCONS_VISITOR_RETURN;
743
292k
        }
744
745
        JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) final
746
368k
        {
747
            // true and false
748
368k
            sink_.push_back(static_cast<uint8_t>(val ? jsoncons::msgpack::msgpack_type::true_type : jsoncons::msgpack::msgpack_type::false_type));
749
750
368k
            end_value();
751
368k
            JSONCONS_VISITOR_RETURN;
752
368k
        }
753
754
        void end_value()
755
1.19M
        {
756
1.19M
            if (!stack_.empty())
757
1.19M
            {
758
1.19M
                ++stack_.back().index_;
759
1.19M
            }
760
1.19M
        }
761
    };
762
763
    using msgpack_stream_encoder = basic_msgpack_encoder<jsoncons::binary_stream_sink>;
764
    using msgpack_bytes_encoder = basic_msgpack_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
765
766
} // namespace msgpack
767
} // namespace jsoncons
768
769
#endif // JSONCONS_EXT_MSGPACK_MSGPACK_ENCODER_HPP