TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/boostorg/json
8 : //
9 :
10 : #ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
11 : #define BOOST_JSON_IMPL_SERIALIZER_IPP
12 :
13 : #include <boost/charconv/to_chars.hpp>
14 : #include <boost/core/detail/static_assert.hpp>
15 : #include <boost/json/serializer.hpp>
16 : #include <boost/json/detail/format.hpp>
17 : #include <boost/json/detail/sse2.hpp>
18 :
19 : #ifdef _MSC_VER
20 : #pragma warning(push)
21 : #pragma warning(disable: 4127) // conditional expression is constant
22 : #endif
23 :
24 : namespace {
25 :
26 : std::size_t
27 : BOOST_NOINLINE
28 HIT 15 : format_special(char* dest, double d, bool allow_infinity_and_nan) noexcept
29 : {
30 15 : if( std::isinf(d) )
31 : {
32 10 : if( std::signbit(d) )
33 : {
34 5 : if( allow_infinity_and_nan )
35 : {
36 2 : std::memcpy(dest, "-Infinity", 9);
37 2 : return 9;
38 : }
39 : else
40 : {
41 3 : std::memcpy(dest, "-1e99999", 8);
42 3 : return 8;
43 : }
44 : }
45 : else
46 : {
47 5 : if( allow_infinity_and_nan )
48 : {
49 2 : std::memcpy(dest, "Infinity", 8);
50 2 : return 8;
51 : }
52 : else
53 : {
54 3 : std::memcpy(dest, "1e99999", 7);
55 3 : return 7;
56 : }
57 : }
58 : }
59 : else
60 : {
61 5 : BOOST_ASSERT( std::isnan(d) );
62 5 : if( allow_infinity_and_nan )
63 : {
64 2 : std::memcpy(dest, "NaN", 3);
65 2 : return 3;
66 : }
67 : else
68 : {
69 3 : std::memcpy(dest, "null", 4);
70 3 : return 4;
71 : }
72 : }
73 : }
74 :
75 : } // namespace
76 :
77 : namespace boost {
78 : namespace json {
79 : namespace detail {
80 :
81 : struct int64_formatter
82 : {
83 : std::int64_t i;
84 :
85 : std::size_t
86 3188 : operator()(char* dst) const noexcept
87 : {
88 3188 : return format_int64(dst, i);
89 : }
90 : };
91 :
92 : struct uint64_formatter
93 : {
94 : std::uint64_t u;
95 :
96 : std::size_t
97 425 : operator()(char* dst) const noexcept
98 : {
99 425 : return format_uint64(dst, u);
100 : }
101 : };
102 :
103 : struct double_formatter
104 : {
105 : double d;
106 : bool allow_infinity_and_nan;
107 :
108 : std::size_t
109 534 : operator()(char* dst) const noexcept
110 : {
111 534 : if(BOOST_JSON_UNLIKELY( !std::isfinite(d)) )
112 : {
113 15 : return format_special(dst, d, allow_infinity_and_nan);
114 : }
115 :
116 519 : auto const result = boost::charconv::to_chars(
117 : dst,
118 : dst + detail::max_number_chars,
119 519 : d,
120 : boost::charconv::chars_format::scientific);
121 519 : BOOST_ASSERT( result.ec == std::errc() );
122 519 : return result.ptr - dst;
123 : }
124 : };
125 :
126 21302 : writer::
127 : writer(
128 : storage_ptr sp,
129 : unsigned char* buf,
130 : std::size_t buf_size,
131 21302 : serialize_options const& opts) noexcept
132 21302 : : st_(
133 21302 : std::move(sp),
134 : buf,
135 : buf_size)
136 21302 : , opts_(opts)
137 : {
138 : // ensure room for \uXXXX escape plus one
139 : BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
140 21302 : }
141 :
142 : bool
143 : BOOST_FORCEINLINE
144 : write_buffer(writer& w, stream& ss0)
145 : {
146 1558 : local_stream ss(ss0);
147 2744 : auto const n = ss.remain();
148 2744 : if( n < w.cs0_.remain() )
149 : {
150 1448 : ss.append(w.cs0_.data(), n);
151 1448 : w.cs0_.skip(n);
152 1448 : return w.suspend(writer::state::lit);
153 : }
154 1296 : ss.append( w.cs0_.data(), w.cs0_.remain() );
155 1296 : return true;
156 2744 : }
157 :
158 : template< class F >
159 : bool
160 4147 : write_buffer(writer& w, stream& ss0, F f)
161 : {
162 4147 : BOOST_ASSERT( w.st_.empty() );
163 :
164 4147 : local_stream ss(ss0);
165 4147 : if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
166 : {
167 2961 : ss.advance( f(ss.data()) );
168 2961 : return true;
169 : }
170 :
171 1186 : w.cs0_ = { w.buf_, f(w.buf_) };
172 1186 : return write_buffer(w, ss);
173 4147 : }
174 :
175 : template<literals Lit>
176 : bool
177 4725 : write_literal(writer& w, stream& ss)
178 : {
179 4725 : constexpr std::size_t index = literal_index(Lit);
180 4725 : constexpr char const* literal = literal_strings[index];
181 4725 : constexpr std::size_t sz = literal_sizes[index];
182 :
183 4725 : std::size_t const n = ss.remain();
184 4725 : if(BOOST_JSON_LIKELY( n >= sz ))
185 : {
186 4613 : ss.append( literal, sz );
187 4613 : return true;
188 : }
189 :
190 112 : ss.append(literal, n);
191 :
192 112 : w.cs0_ = {literal + n, sz - n};
193 112 : return w.suspend(writer::state::lit);
194 : }
195 :
196 : bool
197 197 : write_true(writer& w, stream& ss)
198 : {
199 197 : return write_literal<literals::true_>(w, ss);
200 : }
201 :
202 : bool
203 176 : write_false(writer& w, stream& ss)
204 : {
205 176 : return write_literal<literals::false_>(w, ss);
206 : }
207 :
208 : bool
209 4352 : write_null(writer& w, stream& ss)
210 : {
211 4352 : return write_literal<literals::null>(w, ss);
212 : }
213 :
214 : bool
215 3188 : write_int64(writer& w, stream& ss0, std::int64_t i)
216 : {
217 3188 : return write_buffer( w, ss0, int64_formatter{i} );
218 : }
219 :
220 : bool
221 425 : write_uint64(writer& w, stream& ss0, std::uint64_t u)
222 : {
223 425 : return write_buffer( w, ss0, uint64_formatter{u} );
224 : }
225 :
226 : bool
227 534 : write_double(writer& w, stream& ss0, double d)
228 : {
229 1068 : return write_buffer(
230 534 : w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
231 : }
232 :
233 : bool
234 1558 : resume_buffer(writer& w, stream& ss0)
235 : {
236 1558 : BOOST_ASSERT( !w.st_.empty() );
237 : writer::state st;
238 1558 : w.st_.pop(st);
239 1558 : BOOST_ASSERT(st == writer::state::lit);
240 :
241 3116 : return write_buffer(w, ss0);
242 : }
243 :
244 : template<bool StackEmpty>
245 : bool
246 44285 : do_write_string(writer& w, stream& ss0)
247 : {
248 44285 : local_stream ss(ss0);
249 44285 : local_const_stream cs(w.cs0_);
250 9812 : if(! StackEmpty && ! w.st_.empty())
251 : {
252 : writer::state st;
253 9812 : w.st_.pop(st);
254 9812 : switch(st)
255 : {
256 170 : default:
257 170 : case writer::state::str1: goto do_str1;
258 268 : case writer::state::str2: goto do_str2;
259 9082 : case writer::state::str3: goto do_str3;
260 52 : case writer::state::esc1: goto do_esc1;
261 48 : case writer::state::utf1: goto do_utf1;
262 48 : case writer::state::utf2: goto do_utf2;
263 48 : case writer::state::utf3: goto do_utf3;
264 48 : case writer::state::utf4: goto do_utf4;
265 48 : case writer::state::utf5: goto do_utf5;
266 : }
267 : }
268 : static constexpr char hex[] = "0123456789abcdef";
269 : static constexpr char esc[] =
270 : "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
271 : "\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
272 : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0"
273 : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
274 : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
275 : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
276 : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
277 : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
278 :
279 : // opening quote
280 34473 : do_str1:
281 34643 : if(BOOST_JSON_LIKELY(ss))
282 34473 : ss.append('\x22'); // '"'
283 : else
284 170 : return w.suspend(writer::state::str1);
285 :
286 : // fast loop,
287 : // copy unescaped
288 34741 : do_str2:
289 34741 : if(BOOST_JSON_LIKELY(ss))
290 : {
291 34485 : std::size_t n = cs.remain();
292 34485 : if(BOOST_JSON_LIKELY(n > 0))
293 : {
294 34441 : if(ss.remain() > n)
295 25766 : n = detail::count_unescaped(
296 : cs.data(), n);
297 : else
298 8675 : n = detail::count_unescaped(
299 : cs.data(), ss.remain());
300 34441 : if(n > 0)
301 : {
302 25225 : ss.append(cs.data(), n);
303 25225 : cs.skip(n);
304 25225 : if(! ss)
305 12 : return w.suspend(writer::state::str2);
306 : }
307 : }
308 : else
309 : {
310 44 : ss.append('\x22'); // '"'
311 44 : return true;
312 : }
313 : }
314 : else
315 : {
316 256 : return w.suspend(writer::state::str2);
317 : }
318 :
319 : // slow loop,
320 : // handle escapes
321 43707 : do_str3:
322 31461016 : while(BOOST_JSON_LIKELY(ss))
323 : {
324 31451934 : if(BOOST_JSON_LIKELY(cs))
325 : {
326 31417505 : auto const ch = *cs;
327 31417505 : auto const c = esc[static_cast<
328 : unsigned char>(ch)];
329 31417505 : ++cs;
330 31417505 : if(! c)
331 : {
332 31416777 : ss.append(ch);
333 : }
334 728 : else if(c != 'u')
335 : {
336 376 : ss.append('\\');
337 376 : if(BOOST_JSON_LIKELY(ss))
338 : {
339 324 : ss.append(c);
340 : }
341 : else
342 : {
343 52 : w.buf_[0] = c;
344 52 : return w.suspend(
345 52 : writer::state::esc1);
346 : }
347 : }
348 : else
349 : {
350 352 : if(BOOST_JSON_LIKELY(
351 : ss.remain() >= 6))
352 : {
353 208 : ss.append("\\u00", 4);
354 208 : ss.append(hex[static_cast<
355 208 : unsigned char>(ch) >> 4]);
356 208 : ss.append(hex[static_cast<
357 208 : unsigned char>(ch) & 15]);
358 : }
359 : else
360 : {
361 144 : ss.append('\\');
362 144 : w.buf_[0] = hex[static_cast<
363 144 : unsigned char>(ch) >> 4];
364 144 : w.buf_[1] = hex[static_cast<
365 144 : unsigned char>(ch) & 15];
366 144 : goto do_utf1;
367 : }
368 : }
369 : }
370 : else
371 : {
372 34429 : ss.append('\x22'); // '"'
373 34429 : return true;
374 : }
375 : }
376 9082 : return w.suspend(writer::state::str3);
377 :
378 52 : do_esc1:
379 52 : BOOST_ASSERT(ss);
380 52 : ss.append(w.buf_[0]);
381 52 : goto do_str3;
382 :
383 192 : do_utf1:
384 192 : if(BOOST_JSON_LIKELY(ss))
385 144 : ss.append('u');
386 : else
387 48 : return w.suspend(writer::state::utf1);
388 192 : do_utf2:
389 192 : if(BOOST_JSON_LIKELY(ss))
390 144 : ss.append('0');
391 : else
392 48 : return w.suspend(writer::state::utf2);
393 192 : do_utf3:
394 192 : if(BOOST_JSON_LIKELY(ss))
395 144 : ss.append('0');
396 : else
397 48 : return w.suspend(writer::state::utf3);
398 192 : do_utf4:
399 192 : if(BOOST_JSON_LIKELY(ss))
400 144 : ss.append(w.buf_[0]);
401 : else
402 48 : return w.suspend(writer::state::utf4);
403 192 : do_utf5:
404 192 : if(BOOST_JSON_LIKELY(ss))
405 144 : ss.append(w.buf_[1]);
406 : else
407 48 : return w.suspend(writer::state::utf5);
408 144 : goto do_str3;
409 44285 : }
410 :
411 : bool
412 19827 : write_string(writer& w, stream& ss0)
413 : {
414 19827 : return do_write_string<true>(w, ss0);
415 : }
416 :
417 : bool
418 408 : resume_string(writer& w, stream& ss0)
419 : {
420 408 : return do_write_string<false>(w, ss0);
421 : }
422 :
423 : template<bool StackEmpty>
424 : bool
425 : write_value(writer& w, stream& ss);
426 :
427 : template< class T, bool StackEmpty >
428 : BOOST_FORCEINLINE
429 : bool
430 : write_impl(no_conversion_tag, writer& w, stream& ss)
431 : {
432 34575 : return write_value<StackEmpty>(w, ss);
433 : }
434 :
435 : template<bool StackEmpty>
436 : bool
437 6080 : write_array(writer& w, stream& ss)
438 : {
439 6079 : return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
440 : }
441 :
442 : template<bool StackEmpty>
443 : bool
444 27194 : write_object(writer& w, stream& ss)
445 : {
446 27194 : return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
447 : }
448 :
449 : template<bool StackEmpty>
450 : bool
451 67131 : write_value(writer& w, stream& ss)
452 : {
453 23041 : if(StackEmpty || w.st_.empty())
454 : {
455 44571 : BOOST_ASSERT( w.p_ );
456 44571 : auto const pv = reinterpret_cast<value const*>(w.p_);
457 44571 : switch(pv->kind())
458 : {
459 18083 : default:
460 : case kind::object:
461 18083 : w.p_ = &pv->get_object();
462 18083 : return write_object<true>(w, ss);
463 :
464 3413 : case kind::array:
465 3413 : w.p_ = &pv->get_array();
466 3413 : return write_array<true>(w, ss);
467 :
468 14643 : case kind::string:
469 : {
470 14643 : auto const& js = pv->get_string();
471 14643 : w.cs0_ = { js.data(), js.size() };
472 14643 : return do_write_string<true>(w, ss);
473 : }
474 :
475 3182 : case kind::int64:
476 3182 : return write_int64( w, ss, pv->get_int64() );
477 91 : case kind::uint64:
478 91 : return write_uint64( w, ss, pv->get_uint64() );
479 522 : case kind::double_:
480 522 : return write_double( w, ss, pv->get_double() );
481 :
482 306 : case kind::bool_:
483 306 : if( pv->get_bool() )
484 139 : return write_true(w, ss);
485 : else
486 167 : return write_false(w, ss);
487 :
488 4331 : case kind::null:
489 4331 : return write_null(w, ss);
490 : }
491 : }
492 : else
493 : {
494 : writer::state st;
495 22560 : w.st_.peek(st);
496 22560 : switch(st)
497 : {
498 1434 : default:
499 : case writer::state::lit:
500 1434 : return resume_buffer(w, ss);
501 :
502 9404 : case writer::state::str1: case writer::state::str2:
503 : case writer::state::str3: case writer::state::esc1:
504 : case writer::state::utf1: case writer::state::utf2:
505 : case writer::state::utf3: case writer::state::utf4:
506 : case writer::state::utf5:
507 9404 : return do_write_string<false>(w, ss);
508 :
509 2662 : case writer::state::arr1: case writer::state::arr2:
510 : case writer::state::arr3: case writer::state::arr4:
511 2662 : return write_array<StackEmpty>(w, ss);
512 :
513 9060 : case writer::state::obj1: case writer::state::obj2:
514 : case writer::state::obj3: case writer::state::obj4:
515 : case writer::state::obj5: case writer::state::obj6:
516 9060 : return write_object<StackEmpty>(w, ss);
517 : }
518 : }
519 : }
520 :
521 : } // namespace detail
522 :
523 2405 : serializer::
524 2405 : serializer(serialize_options const& opts) noexcept
525 2405 : : serializer({}, nullptr, 0, opts)
526 2405 : {}
527 :
528 21302 : serializer::
529 : serializer(
530 : storage_ptr sp,
531 : unsigned char* buf,
532 : std::size_t buf_size,
533 21302 : serialize_options const& opts) noexcept
534 21302 : : detail::writer(std::move(sp), buf, buf_size, opts)
535 21302 : {}
536 :
537 : void
538 21016 : serializer::
539 : reset(value const* p) noexcept
540 : {
541 21016 : p_ = p;
542 21016 : fn0_ = &detail::write_value<true>;
543 21016 : fn1_ = &detail::write_value<false>;
544 21016 : st_.clear();
545 21016 : done_ = false;
546 21016 : }
547 :
548 : void
549 5 : serializer::
550 : reset(array const* p) noexcept
551 : {
552 5 : p_ = p;
553 5 : fn0_ = &detail::write_array<true>;
554 5 : fn1_ = &detail::write_array<false>;
555 5 : st_.clear();
556 5 : done_ = false;
557 5 : }
558 :
559 : void
560 51 : serializer::
561 : reset(object const* p) noexcept
562 : {
563 51 : p_ = p;
564 51 : fn0_ = &detail::write_object<true>;
565 51 : fn1_ = &detail::write_object<false>;
566 51 : st_.clear();
567 51 : done_ = false;
568 51 : }
569 :
570 : void
571 2 : serializer::
572 : reset(string const* p) noexcept
573 : {
574 2 : cs0_ = { p->data(), p->size() };
575 2 : fn0_ = &detail::do_write_string<true>;
576 2 : fn1_ = &detail::do_write_string<false>;
577 2 : st_.clear();
578 2 : done_ = false;
579 2 : }
580 :
581 : void
582 1 : serializer::
583 : reset(string_view sv) noexcept
584 : {
585 1 : cs0_ = { sv.data(), sv.size() };
586 1 : fn0_ = &detail::do_write_string<true>;
587 1 : fn1_ = &detail::do_write_string<false>;
588 1 : st_.clear();
589 1 : done_ = false;
590 1 : }
591 :
592 : void
593 6 : serializer::reset(std::nullptr_t) noexcept
594 : {
595 6 : p_ = nullptr;
596 6 : fn0_ = &detail::write_impl<std::nullptr_t, true>;
597 6 : fn1_ = &detail::write_impl<std::nullptr_t, false>;
598 6 : st_.clear();
599 6 : done_ = false;
600 6 : }
601 :
602 : string_view
603 33154 : serializer::
604 : read(char* dest, std::size_t size)
605 : {
606 33154 : if( !fn0_ )
607 6 : reset(nullptr);
608 :
609 33154 : if(BOOST_JSON_UNLIKELY(size == 0))
610 1 : return {dest, 0};
611 :
612 33153 : detail::stream ss(dest, size);
613 33153 : if(st_.empty())
614 21301 : fn0_(*this, ss);
615 : else
616 11852 : fn1_(*this, ss);
617 33151 : if(st_.empty())
618 : {
619 21299 : done_ = true;
620 21299 : fn0_ = nullptr;
621 21299 : p_ = nullptr;
622 : }
623 33151 : return string_view(
624 33151 : dest, ss.used(dest));
625 : }
626 :
627 : } // namespace json
628 : } // namespace boost
629 :
630 : #ifdef _MSC_VER
631 : #pragma warning(pop)
632 : #endif
633 :
634 : #endif
|