/src/jsoncons/include/jsoncons_ext/msgpack/msgpack_encoder.hpp
Line | Count | Source |
1 | | // Copyright 2013-2026 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 | 133k | : type_(type), length_(length) |
65 | 133k | { |
66 | 133k | } |
67 | | |
68 | | std::size_t length() const |
69 | 222k | { |
70 | 222k | return length_; |
71 | 222k | } |
72 | | |
73 | | std::size_t count() const |
74 | 222k | { |
75 | 222k | return is_object() ? index_/2 : index_; |
76 | 222k | } |
77 | | |
78 | | bool is_object() const |
79 | 222k | { |
80 | 222k | return type_ == msgpack_container_type::object; |
81 | 222k | } |
82 | | }; |
83 | | |
84 | | Sink sink_; |
85 | | int max_nesting_depth_; |
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.18k | : basic_msgpack_encoder(std::forward<Sink>(sink), msgpack_encode_options(), alloc) |
98 | 6.18k | { |
99 | 6.18k | } |
100 | | |
101 | | explicit basic_msgpack_encoder(Sink&& sink, |
102 | | const msgpack_encode_options& options, |
103 | | const Allocator& alloc = Allocator()) |
104 | 6.18k | : sink_(std::forward<Sink>(sink)), |
105 | 6.18k | max_nesting_depth_(options.max_nesting_depth()), |
106 | 6.18k | alloc_(alloc) |
107 | 6.18k | { |
108 | 6.18k | } |
109 | | |
110 | | ~basic_msgpack_encoder() noexcept |
111 | 6.18k | { |
112 | 6.18k | sink_.flush(); |
113 | 6.18k | } |
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.50k | { |
135 | 1.50k | sink_.flush(); |
136 | 1.50k | } |
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 | 46.9k | { |
146 | 46.9k | if (JSONCONS_UNLIKELY(++nesting_depth_ > max_nesting_depth_)) |
147 | 0 | { |
148 | 0 | ec = msgpack_errc::max_nesting_depth_exceeded; |
149 | 0 | JSONCONS_VISITOR_RETURN; |
150 | 0 | } |
151 | 46.9k | stack_.emplace_back(msgpack_container_type::object, length); |
152 | | |
153 | 46.9k | if (length <= 15) |
154 | 45.4k | { |
155 | | // fixmap |
156 | 45.4k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixmap_base_type | (length & 0xf)); |
157 | 45.4k | } |
158 | 1.53k | else if (length <= 65535) |
159 | 719 | { |
160 | | // map 16 |
161 | 719 | sink_.push_back(jsoncons::msgpack::msgpack_type::map16_type); |
162 | 719 | binary::native_to_big(static_cast<uint16_t>(length), |
163 | 719 | std::back_inserter(sink_)); |
164 | 719 | } |
165 | 814 | else if (length <= (std::numeric_limits<uint32_t>::max)()) |
166 | 814 | { |
167 | | // map 32 |
168 | 814 | sink_.push_back(jsoncons::msgpack::msgpack_type::map32_type); |
169 | 814 | binary::native_to_big(static_cast<uint32_t>(length), |
170 | 814 | std::back_inserter(sink_)); |
171 | 814 | } |
172 | | |
173 | 46.9k | JSONCONS_VISITOR_RETURN; |
174 | 46.9k | } |
175 | | |
176 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_object(const ser_context&, std::error_code& ec) final |
177 | 39.4k | { |
178 | 39.4k | JSONCONS_ASSERT(!stack_.empty()); |
179 | 39.4k | --nesting_depth_; |
180 | | |
181 | 39.4k | if (stack_.back().count() < stack_.back().length()) |
182 | 424 | { |
183 | 424 | ec = msgpack_errc::too_few_items; |
184 | 424 | JSONCONS_VISITOR_RETURN; |
185 | 424 | } |
186 | 39.0k | 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 | 39.0k | stack_.pop_back(); |
193 | 39.0k | end_value(); |
194 | 39.0k | JSONCONS_VISITOR_RETURN; |
195 | 39.4k | } |
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 | 86.1k | { |
205 | 86.1k | if (JSONCONS_UNLIKELY(++nesting_depth_ > max_nesting_depth_)) |
206 | 0 | { |
207 | 0 | ec = msgpack_errc::max_nesting_depth_exceeded; |
208 | 0 | JSONCONS_VISITOR_RETURN; |
209 | 0 | } |
210 | 86.1k | stack_.emplace_back(msgpack_container_type::array, length); |
211 | 86.1k | if (length <= 15) |
212 | 83.4k | { |
213 | | // fixarray |
214 | 83.4k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixarray_base_type | (length & 0xf)); |
215 | 83.4k | } |
216 | 2.70k | else if (length <= (std::numeric_limits<uint16_t>::max)()) |
217 | 1.60k | { |
218 | | // array 16 |
219 | 1.60k | sink_.push_back(jsoncons::msgpack::msgpack_type::array16_type); |
220 | 1.60k | binary::native_to_big(static_cast<uint16_t>(length),std::back_inserter(sink_)); |
221 | 1.60k | } |
222 | 1.09k | else if (length <= (std::numeric_limits<uint32_t>::max)()) |
223 | 1.09k | { |
224 | | // array 32 |
225 | 1.09k | sink_.push_back(jsoncons::msgpack::msgpack_type::array32_type); |
226 | 1.09k | binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); |
227 | 1.09k | } |
228 | 86.1k | JSONCONS_VISITOR_RETURN; |
229 | 86.1k | } |
230 | | |
231 | | JSONCONS_VISITOR_RETURN_TYPE visit_end_array(const ser_context&, std::error_code& ec) final |
232 | 72.0k | { |
233 | 72.0k | JSONCONS_ASSERT(!stack_.empty()); |
234 | | |
235 | 72.0k | --nesting_depth_; |
236 | | |
237 | 72.0k | if (stack_.back().count() < stack_.back().length()) |
238 | 482 | { |
239 | 482 | ec = msgpack_errc::too_few_items; |
240 | 482 | JSONCONS_VISITOR_RETURN; |
241 | 482 | } |
242 | 71.5k | 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 | 71.5k | stack_.pop_back(); |
249 | 71.5k | end_value(); |
250 | 71.5k | JSONCONS_VISITOR_RETURN; |
251 | 72.0k | } |
252 | | |
253 | | JSONCONS_VISITOR_RETURN_TYPE visit_key(const string_view_type& name, const ser_context& context, std::error_code& ec) override |
254 | 238k | { |
255 | 238k | visit_string(name, semantic_tag::none, context, ec); |
256 | 238k | JSONCONS_VISITOR_RETURN; |
257 | 238k | } |
258 | | |
259 | | JSONCONS_VISITOR_RETURN_TYPE visit_null(semantic_tag, const ser_context&, std::error_code&) final |
260 | 12.6k | { |
261 | | // nil |
262 | 12.6k | sink_.push_back(jsoncons::msgpack::msgpack_type::nil_type); |
263 | 12.6k | end_value(); |
264 | 12.6k | JSONCONS_VISITOR_RETURN; |
265 | 12.6k | } |
266 | | |
267 | | void write_timestamp(int64_t seconds, int64_t nanoseconds) |
268 | 13.9k | { |
269 | 13.9k | if ((seconds >> 34) == 0) |
270 | 9.51k | { |
271 | 9.51k | uint64_t data64 = (nanoseconds << 34) | seconds; |
272 | 9.51k | if ((data64 & 0xffffffff00000000L) == 0) |
273 | 7.32k | { |
274 | | // timestamp 32 |
275 | 7.32k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type); |
276 | 7.32k | sink_.push_back(0xff); |
277 | 7.32k | binary::native_to_big(static_cast<uint32_t>(data64), std::back_inserter(sink_)); |
278 | 7.32k | } |
279 | 2.19k | else |
280 | 2.19k | { |
281 | | // timestamp 64 |
282 | 2.19k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type); |
283 | 2.19k | sink_.push_back(0xff); |
284 | 2.19k | binary::native_to_big(static_cast<uint64_t>(data64), std::back_inserter(sink_)); |
285 | 2.19k | } |
286 | 9.51k | } |
287 | 4.43k | else |
288 | 4.43k | { |
289 | | // timestamp 96 |
290 | 4.43k | sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type); |
291 | 4.43k | sink_.push_back(0x0c); // 12 |
292 | 4.43k | sink_.push_back(0xff); |
293 | 4.43k | binary::native_to_big(static_cast<uint32_t>(nanoseconds), std::back_inserter(sink_)); |
294 | 4.43k | binary::native_to_big(static_cast<uint64_t>(seconds), std::back_inserter(sink_)); |
295 | 4.43k | } |
296 | 13.9k | } |
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 | 248k | { |
300 | 248k | switch (tag) |
301 | 248k | { |
302 | 0 | case semantic_tag::epoch_second: |
303 | 0 | { |
304 | 0 | int64_t seconds; |
305 | 0 | auto result = jsoncons::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 | 7.46k | case semantic_tag::epoch_nano: |
343 | 7.46k | { |
344 | 7.46k | bigint n; |
345 | 7.46k | auto result = to_bigint(sv.data(), sv.length(), n); |
346 | 7.46k | if (!result) |
347 | 0 | { |
348 | 0 | ec = msgpack_errc::invalid_timestamp; |
349 | 0 | JSONCONS_VISITOR_RETURN; |
350 | 0 | } |
351 | 7.46k | if (n != 0) |
352 | 6.64k | { |
353 | 6.64k | bigint q; |
354 | 6.64k | bigint rem; |
355 | 6.64k | n.divide(nanos_in_second, q, rem, true); |
356 | 6.64k | auto seconds = static_cast<int64_t>(q); |
357 | 6.64k | auto nanoseconds = static_cast<int64_t>(rem); |
358 | 6.64k | if (nanoseconds < 0) |
359 | 1.43k | { |
360 | 1.43k | nanoseconds = -nanoseconds; |
361 | 1.43k | } |
362 | 6.64k | write_timestamp(seconds, nanoseconds); |
363 | 6.64k | } |
364 | 820 | else |
365 | 820 | { |
366 | 820 | write_timestamp(0, 0); |
367 | 820 | } |
368 | 7.46k | break; |
369 | 7.46k | } |
370 | 241k | default: |
371 | 241k | { |
372 | 241k | write_string_value(sv); |
373 | 241k | end_value(); |
374 | 241k | break; |
375 | 7.46k | } |
376 | 248k | } |
377 | 248k | JSONCONS_VISITOR_RETURN; |
378 | 248k | } |
379 | | |
380 | | void write_string_value(const string_view_type& sv) |
381 | 241k | { |
382 | 241k | auto sink = unicode_traits::validate(sv.data(), sv.size()); |
383 | 241k | 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 | 241k | const size_t length = sv.length(); |
389 | 241k | if (length <= 31) |
390 | 238k | { |
391 | | // fixstr stores a byte array whose length is upto 31 bytes |
392 | 238k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixstr_base_type | static_cast<uint8_t>(length)); |
393 | 238k | } |
394 | 2.36k | else if (length <= (std::numeric_limits<uint8_t>::max)()) |
395 | 1.33k | { |
396 | | // str 8 stores a byte array whose length is upto (2^8)-1 bytes |
397 | 1.33k | sink_.push_back(jsoncons::msgpack::msgpack_type::str8_type); |
398 | 1.33k | sink_.push_back(static_cast<uint8_t>(length)); |
399 | 1.33k | } |
400 | 1.03k | else if (length <= (std::numeric_limits<uint16_t>::max)()) |
401 | 712 | { |
402 | | // str 16 stores a byte array whose length is upto (2^16)-1 bytes |
403 | 712 | sink_.push_back(jsoncons::msgpack::msgpack_type::str16_type); |
404 | 712 | binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); |
405 | 712 | } |
406 | 323 | else if (length <= (std::numeric_limits<uint32_t>::max)()) |
407 | 323 | { |
408 | | // str 32 stores a byte array whose length is upto (2^32)-1 bytes |
409 | 323 | sink_.push_back(jsoncons::msgpack::msgpack_type::str32_type); |
410 | 323 | binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); |
411 | 323 | } |
412 | | |
413 | 241k | for (auto c : sv) |
414 | 91.5M | { |
415 | 91.5M | sink_.push_back(c); |
416 | 91.5M | } |
417 | 241k | } |
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.76k | { |
424 | | |
425 | 2.76k | const std::size_t length = b.size(); |
426 | 2.76k | if (length <= (std::numeric_limits<uint8_t>::max)()) |
427 | 2.26k | { |
428 | | // bin 8 stores a byte array whose length is upto (2^8)-1 bytes |
429 | 2.26k | sink_.push_back(jsoncons::msgpack::msgpack_type::bin8_type); |
430 | 2.26k | sink_.push_back(static_cast<uint8_t>(length)); |
431 | 2.26k | } |
432 | 501 | else if (length <= (std::numeric_limits<uint16_t>::max)()) |
433 | 438 | { |
434 | | // bin 16 stores a byte array whose length is upto (2^16)-1 bytes |
435 | 438 | sink_.push_back(jsoncons::msgpack::msgpack_type::bin16_type); |
436 | 438 | binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); |
437 | 438 | } |
438 | 63 | else if (length <= (std::numeric_limits<uint32_t>::max)()) |
439 | 63 | { |
440 | | // bin 32 stores a byte array whose length is upto (2^32)-1 bytes |
441 | 63 | sink_.push_back(jsoncons::msgpack::msgpack_type::bin32_type); |
442 | 63 | binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); |
443 | 63 | } |
444 | | |
445 | 2.76k | for (auto c : b) |
446 | 8.41M | { |
447 | 8.41M | sink_.push_back(c); |
448 | 8.41M | } |
449 | | |
450 | 2.76k | end_value(); |
451 | 2.76k | JSONCONS_VISITOR_RETURN; |
452 | 2.76k | } |
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 | 106k | { |
459 | 106k | const std::size_t length = b.size(); |
460 | 106k | switch (length) |
461 | 106k | { |
462 | 1.92k | case 1: |
463 | 1.92k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext1_type); |
464 | 1.92k | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
465 | 1.92k | break; |
466 | 97.0k | case 2: |
467 | 97.0k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext2_type); |
468 | 97.0k | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
469 | 97.0k | break; |
470 | 643 | case 4: |
471 | 643 | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type); |
472 | 643 | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
473 | 643 | break; |
474 | 2.17k | case 8: |
475 | 2.17k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type); |
476 | 2.17k | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
477 | 2.17k | break; |
478 | 3.15k | case 16: |
479 | 3.15k | sink_.push_back(jsoncons::msgpack::msgpack_type::fixext16_type); |
480 | 3.15k | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
481 | 3.15k | break; |
482 | 1.86k | default: |
483 | 1.86k | if (length <= (std::numeric_limits<uint8_t>::max)()) |
484 | 1.37k | { |
485 | 1.37k | sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type); |
486 | 1.37k | sink_.push_back(static_cast<uint8_t>(length)); |
487 | 1.37k | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
488 | 1.37k | } |
489 | 490 | else if (length <= (std::numeric_limits<uint16_t>::max)()) |
490 | 408 | { |
491 | 408 | sink_.push_back(jsoncons::msgpack::msgpack_type::ext16_type); |
492 | 408 | binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); |
493 | 408 | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
494 | 408 | } |
495 | 82 | else if (length <= (std::numeric_limits<uint32_t>::max)()) |
496 | 82 | { |
497 | 82 | sink_.push_back(jsoncons::msgpack::msgpack_type::ext32_type); |
498 | 82 | binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); |
499 | 82 | sink_.push_back(static_cast<uint8_t>(ext_tag)); |
500 | 82 | } |
501 | 1.86k | break; |
502 | 106k | } |
503 | | |
504 | 106k | for (auto c : b) |
505 | 8.99M | { |
506 | 8.99M | sink_.push_back(c); |
507 | 8.99M | } |
508 | | |
509 | 106k | end_value(); |
510 | 106k | JSONCONS_VISITOR_RETURN; |
511 | 106k | } |
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.5k | { |
521 | | // float 32 |
522 | 37.5k | sink_.push_back(jsoncons::msgpack::msgpack_type::float32_type); |
523 | 37.5k | binary::native_to_big(valf,std::back_inserter(sink_)); |
524 | 37.5k | } |
525 | 5.59k | else |
526 | 5.59k | { |
527 | | // float 64 |
528 | 5.59k | sink_.push_back(jsoncons::msgpack::msgpack_type::float64_type); |
529 | 5.59k | binary::native_to_big(val,std::back_inserter(sink_)); |
530 | 5.59k | } |
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 | 166k | { |
543 | 166k | switch (tag) |
544 | 166k | { |
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 | 166k | default: |
587 | 166k | { |
588 | 166k | if (val >= 0) |
589 | 8.96k | { |
590 | 8.96k | if (val <= 0x7f) |
591 | 340 | { |
592 | | // positive fixnum stores 7-bit positive integer |
593 | 340 | sink_.push_back(static_cast<uint8_t>(val)); |
594 | 340 | } |
595 | 8.62k | else if (val <= (std::numeric_limits<uint8_t>::max)()) |
596 | 525 | { |
597 | | // uint 8 stores a 8-bit unsigned integer |
598 | 525 | sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type); |
599 | 525 | sink_.push_back(static_cast<uint8_t>(val)); |
600 | 525 | } |
601 | 8.10k | else if (val <= (std::numeric_limits<uint16_t>::max)()) |
602 | 440 | { |
603 | | // uint 16 stores a 16-bit big-endian unsigned integer |
604 | 440 | sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type); |
605 | 440 | binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_)); |
606 | 440 | } |
607 | 7.66k | else if (val <= (std::numeric_limits<uint32_t>::max)()) |
608 | 310 | { |
609 | | // uint 32 stores a 32-bit big-endian unsigned integer |
610 | 310 | sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type); |
611 | 310 | binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_)); |
612 | 310 | } |
613 | 7.35k | else if (val <= (std::numeric_limits<int64_t>::max)()) |
614 | 7.35k | { |
615 | | // int 64 stores a 64-bit big-endian signed integer |
616 | 7.35k | sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type); |
617 | 7.35k | binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_)); |
618 | 7.35k | } |
619 | 8.96k | } |
620 | 157k | else |
621 | 157k | { |
622 | 157k | if (val >= -32) |
623 | 101k | { |
624 | | // negative fixnum stores 5-bit negative integer |
625 | 101k | binary::native_to_big(static_cast<int8_t>(val), std::back_inserter(sink_)); |
626 | 101k | } |
627 | 55.8k | else if (val >= (std::numeric_limits<int8_t>::lowest)()) |
628 | 34.8k | { |
629 | | // int 8 stores a 8-bit signed integer |
630 | 34.8k | sink_.push_back(jsoncons::msgpack::msgpack_type::int8_type); |
631 | 34.8k | binary::native_to_big(static_cast<int8_t>(val),std::back_inserter(sink_)); |
632 | 34.8k | } |
633 | 20.9k | else if (val >= (std::numeric_limits<int16_t>::lowest)()) |
634 | 13.2k | { |
635 | | // int 16 stores a 16-bit big-endian signed integer |
636 | 13.2k | sink_.push_back(jsoncons::msgpack::msgpack_type::int16_type); |
637 | 13.2k | binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_)); |
638 | 13.2k | } |
639 | 7.78k | else if (val >= (std::numeric_limits<int32_t>::lowest)()) |
640 | 6.18k | { |
641 | | // int 32 stores a 32-bit big-endian signed integer |
642 | 6.18k | sink_.push_back(jsoncons::msgpack::msgpack_type::int32_type); |
643 | 6.18k | binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_)); |
644 | 6.18k | } |
645 | 1.60k | else if (val >= (std::numeric_limits<int64_t>::lowest)()) |
646 | 1.60k | { |
647 | | // int 64 stores a 64-bit big-endian signed integer |
648 | 1.60k | sink_.push_back(jsoncons::msgpack::msgpack_type::int64_type); |
649 | 1.60k | binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_)); |
650 | 1.60k | } |
651 | 157k | } |
652 | 166k | } |
653 | 166k | break; |
654 | 166k | } |
655 | 166k | end_value(); |
656 | 166k | JSONCONS_VISITOR_RETURN; |
657 | 166k | } |
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 | 327k | { |
664 | 327k | switch (tag) |
665 | 327k | { |
666 | 6.48k | case semantic_tag::epoch_second: |
667 | 6.48k | write_timestamp(static_cast<int64_t>(val), 0); |
668 | 6.48k | 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 | 321k | default: |
708 | 321k | { |
709 | 321k | if (val <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)())) |
710 | 283k | { |
711 | | // positive fixnum stores 7-bit positive integer |
712 | 283k | sink_.push_back(static_cast<uint8_t>(val)); |
713 | 283k | } |
714 | 37.6k | else if (val <= (std::numeric_limits<uint8_t>::max)()) |
715 | 13.9k | { |
716 | | // uint 8 stores a 8-bit unsigned integer |
717 | 13.9k | sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type); |
718 | 13.9k | sink_.push_back(static_cast<uint8_t>(val)); |
719 | 13.9k | } |
720 | 23.6k | else if (val <= (std::numeric_limits<uint16_t>::max)()) |
721 | 19.1k | { |
722 | | // uint 16 stores a 16-bit big-endian unsigned integer |
723 | 19.1k | sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type); |
724 | 19.1k | binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_)); |
725 | 19.1k | } |
726 | 4.53k | else if (val <= (std::numeric_limits<uint32_t>::max)()) |
727 | 3.25k | { |
728 | | // uint 32 stores a 32-bit big-endian unsigned integer |
729 | 3.25k | sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type); |
730 | 3.25k | binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_)); |
731 | 3.25k | } |
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 | 321k | break; |
739 | 0 | } |
740 | 327k | } |
741 | 327k | end_value(); |
742 | 327k | JSONCONS_VISITOR_RETURN; |
743 | 327k | } |
744 | | |
745 | | JSONCONS_VISITOR_RETURN_TYPE visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) final |
746 | 251k | { |
747 | | // true and false |
748 | 251k | sink_.push_back(static_cast<uint8_t>(val ? jsoncons::msgpack::msgpack_type::true_type : jsoncons::msgpack::msgpack_type::false_type)); |
749 | | |
750 | 251k | end_value(); |
751 | 251k | JSONCONS_VISITOR_RETURN; |
752 | 251k | } |
753 | | |
754 | | void end_value() |
755 | 1.26M | { |
756 | 1.26M | if (!stack_.empty()) |
757 | 1.26M | { |
758 | 1.26M | ++stack_.back().index_; |
759 | 1.26M | } |
760 | 1.26M | } |
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 |