/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 |