impl/serializer.ipp

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