impl/serializer.ipp

99.6% Lines (266/267) 100.0% List of functions (36/36)
serializer.ipp
f(x) Functions (36)
Function Calls Lines Blocks
boost::json::detail::int64_formatter::operator()(char*) const :32 3188x 100.0% 100.0% boost::json::detail::uint64_formatter::operator()(char*) const :43 425x 100.0% 100.0% boost::json::detail::double_formatter::operator()(char*) const :55 477x 100.0% 100.0% boost::json::detail::writer::writer(boost::json::storage_ptr, unsigned char*, unsigned long, boost::json::serialize_options const&) :61 21301x 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) :95 477x 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) :95 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) :95 425x 100.0% 84.0% bool boost::json::detail::write_literal<(boost::json::detail::literals)0>(boost::json::detail::writer&, boost::json::detail::stream&) :112 4352x 100.0% 100.0% bool boost::json::detail::write_literal<(boost::json::detail::literals)1>(boost::json::detail::writer&, boost::json::detail::stream&) :112 197x 100.0% 100.0% bool boost::json::detail::write_literal<(boost::json::detail::literals)2>(boost::json::detail::writer&, boost::json::detail::stream&) :112 176x 100.0% 100.0% boost::json::detail::write_true(boost::json::detail::writer&, boost::json::detail::stream&) :132 197x 100.0% 100.0% boost::json::detail::write_false(boost::json::detail::writer&, boost::json::detail::stream&) :138 176x 100.0% 100.0% boost::json::detail::write_null(boost::json::detail::writer&, boost::json::detail::stream&) :144 4352x 100.0% 100.0% boost::json::detail::write_int64(boost::json::detail::writer&, boost::json::detail::stream&, long) :150 3188x 100.0% 100.0% boost::json::detail::write_uint64(boost::json::detail::writer&, boost::json::detail::stream&, unsigned long) :156 425x 100.0% 100.0% boost::json::detail::write_double(boost::json::detail::writer&, boost::json::detail::stream&, double) :162 477x 100.0% 100.0% boost::json::detail::resume_buffer(boost::json::detail::writer&, boost::json::detail::stream&) :169 1444x 100.0% 82.0% bool boost::json::detail::do_write_string<false>(boost::json::detail::writer&, boost::json::detail::stream&) :181 9882x 94.7% 89.0% bool boost::json::detail::do_write_string<true>(boost::json::detail::writer&, boost::json::detail::stream&) :181 34629x 96.1% 93.0% boost::json::detail::write_string(boost::json::detail::writer&, boost::json::detail::stream&) :354 19881x 100.0% 100.0% boost::json::detail::resume_string(boost::json::detail::writer&, boost::json::detail::stream&) :360 420x 100.0% 100.0% bool boost::json::detail::write_array<false>(boost::json::detail::writer&, boost::json::detail::stream&) :379 2664x 100.0% 77.0% bool boost::json::detail::write_array<true>(boost::json::detail::writer&, boost::json::detail::stream&) :379 3424x 100.0% 98.0% bool boost::json::detail::write_object<false>(boost::json::detail::writer&, boost::json::detail::stream&) :386 9104x 100.0% 83.0% bool boost::json::detail::write_object<true>(boost::json::detail::writer&, boost::json::detail::stream&) :386 18161x 100.0% 93.0% bool boost::json::detail::write_value<false>(boost::json::detail::writer&, boost::json::detail::stream&) :393 23064x 86.8% 82.0% bool boost::json::detail::write_value<true>(boost::json::detail::writer&, boost::json::detail::stream&) :393 44141x 100.0% 97.0% boost::json::serializer::serializer(boost::json::serialize_options const&) :466 2395x 100.0% 100.0% boost::json::serializer::serializer(boost::json::storage_ptr, unsigned char*, unsigned long, boost::json::serialize_options const&) :471 21301x 100.0% 100.0% boost::json::serializer::reset(boost::json::value const*) :481 21017x 100.0% 100.0% boost::json::serializer::reset(boost::json::array const*) :492 5x 100.0% 100.0% boost::json::serializer::reset(boost::json::object const*) :503 51x 100.0% 100.0% boost::json::serializer::reset(boost::json::string const*) :514 2x 100.0% 100.0% boost::json::serializer::reset(boost::core::basic_string_view<char>) :526 1x 100.0% 100.0% boost::json::serializer::reset(decltype(nullptr)) :538 6x 100.0% 100.0% boost::json::serializer::read(char*, unsigned long) :548 33121x 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/core/detail/static_assert.hpp>
14 #include <boost/json/serializer.hpp>
15 #include <boost/json/detail/format.hpp>
16 #include <boost/json/detail/sse2.hpp>
17
18 #ifdef _MSC_VER
19 #pragma warning(push)
20 #pragma warning(disable: 4127) // conditional expression is constant
21 #endif
22
23 namespace boost {
24 namespace json {
25 namespace detail {
26
27 struct int64_formatter
28 {
29 std::int64_t i;
30
31 std::size_t
32 3188x operator()(char* dst) const noexcept
33 {
34 3188x return format_int64(dst, i);
35 }
36 };
37
38 struct uint64_formatter
39 {
40 std::uint64_t u;
41
42 std::size_t
43 425x operator()(char* dst) const noexcept
44 {
45 425x return format_uint64(dst, u);
46 }
47 };
48
49 struct double_formatter
50 {
51 double d;
52 bool allow_infinity_and_nan;
53
54 std::size_t
55 477x operator()(char* dst) const noexcept
56 {
57 477x return format_double(dst, d, allow_infinity_and_nan);
58 }
59 };
60
61 21301x writer::
62 writer(
63 storage_ptr sp,
64 unsigned char* buf,
65 std::size_t buf_size,
66 21301x serialize_options const& opts) noexcept
67 21301x : st_(
68 21301x std::move(sp),
69 buf,
70 buf_size)
71 21301x , opts_(opts)
72 {
73 // ensure room for \uXXXX escape plus one
74 BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
75 21301x }
76
77 bool
78 BOOST_FORCEINLINE
79 write_buffer(writer& w, stream& ss0)
80 {
81 1444x local_stream ss(ss0);
82 2578x auto const n = ss.remain();
83 2578x if( n < w.cs0_.remain() )
84 {
85 1334x ss.append(w.cs0_.data(), n);
86 1334x w.cs0_.skip(n);
87 1334x return w.suspend(writer::state::lit);
88 }
89 1244x ss.append( w.cs0_.data(), w.cs0_.remain() );
90 1244x return true;
91 2578x }
92
93 template< class F >
94 bool
95 4090x write_buffer(writer& w, stream& ss0, F f)
96 {
97 4090x BOOST_ASSERT( w.st_.empty() );
98
99 4090x local_stream ss(ss0);
100 4090x if(BOOST_JSON_LIKELY( ss.remain() >= detail::max_number_chars ))
101 {
102 2956x ss.advance( f(ss.data()) );
103 2956x return true;
104 }
105
106 1134x w.cs0_ = { w.buf_, f(w.buf_) };
107 1134x return write_buffer(w, ss);
108 4090x }
109
110 template<literals Lit>
111 bool
112 4725x write_literal(writer& w, stream& ss)
113 {
114 4725x constexpr std::size_t index = literal_index(Lit);
115 4725x constexpr char const* literal = literal_strings[index];
116 4725x constexpr std::size_t sz = literal_sizes[index];
117
118 4725x std::size_t const n = ss.remain();
119 4725x if(BOOST_JSON_LIKELY( n >= sz ))
120 {
121 4613x ss.append( literal, sz );
122 4613x return true;
123 }
124
125 112x ss.append(literal, n);
126
127 112x w.cs0_ = {literal + n, sz - n};
128 112x return w.suspend(writer::state::lit);
129 }
130
131 bool
132 197x write_true(writer& w, stream& ss)
133 {
134 197x return write_literal<literals::true_>(w, ss);
135 }
136
137 bool
138 176x write_false(writer& w, stream& ss)
139 {
140 176x return write_literal<literals::false_>(w, ss);
141 }
142
143 bool
144 4352x write_null(writer& w, stream& ss)
145 {
146 4352x return write_literal<literals::null>(w, ss);
147 }
148
149 bool
150 3188x write_int64(writer& w, stream& ss0, std::int64_t i)
151 {
152 3188x return write_buffer( w, ss0, int64_formatter{i} );
153 }
154
155 bool
156 425x write_uint64(writer& w, stream& ss0, std::uint64_t u)
157 {
158 425x return write_buffer( w, ss0, uint64_formatter{u} );
159 }
160
161 bool
162 477x write_double(writer& w, stream& ss0, double d)
163 {
164 954x return write_buffer(
165 477x w, ss0, double_formatter{d, w.opts_.allow_infinity_and_nan} );
166 }
167
168 bool
169 1444x resume_buffer(writer& w, stream& ss0)
170 {
171 1444x BOOST_ASSERT( !w.st_.empty() );
172 writer::state st;
173 1444x w.st_.pop(st);
174 1444x BOOST_ASSERT(st == writer::state::lit);
175
176 2888x return write_buffer(w, ss0);
177 }
178
179 template<bool StackEmpty>
180 bool
181 44511x do_write_string(writer& w, stream& ss0)
182 {
183 44511x local_stream ss(ss0);
184 44511x local_const_stream cs(w.cs0_);
185 9882x if(! StackEmpty && ! w.st_.empty())
186 {
187 writer::state st;
188 9882x w.st_.pop(st);
189 9882x switch(st)
190 {
191 182x default:
192 182x case writer::state::str1: goto do_str1;
193 282x case writer::state::str2: goto do_str2;
194 9126x case writer::state::str3: goto do_str3;
195 52x case writer::state::esc1: goto do_esc1;
196 48x case writer::state::utf1: goto do_utf1;
197 48x case writer::state::utf2: goto do_utf2;
198 48x case writer::state::utf3: goto do_utf3;
199 48x case writer::state::utf4: goto do_utf4;
200 48x case writer::state::utf5: goto do_utf5;
201 }
202 }
203 static constexpr char hex[] = "0123456789abcdef";
204 static constexpr char esc[] =
205 "uuuuuuuubtnufruuuuuuuuuuuuuuuuuu"
206 "\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"
207 "\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"
208 "\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"
209 "\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"
210 "\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"
211 "\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"
212 "\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";
213
214 // opening quote
215 34629x if(w.buf_[2] == false)
216 {
217 34629x do_str1:
218 34811x if(BOOST_JSON_LIKELY(ss))
219 34629x ss.append('\x22'); // '"'
220 else
221 182x return w.suspend(writer::state::str1);
222 }
223
224 // fast loop,
225 // copy unescaped
226 do_str2:
227 34911x if(BOOST_JSON_LIKELY(ss))
228 {
229 34641x std::size_t n = cs.remain();
230 34641x if(BOOST_JSON_LIKELY(n > 0))
231 {
232 34597x if(ss.remain() > n)
233 25893x n = detail::count_unescaped(
234 cs.data(), n);
235 else
236 8704x n = detail::count_unescaped(
237 cs.data(), ss.remain());
238 34597x if(n > 0)
239 {
240 25225x ss.append(cs.data(), n);
241 25225x cs.skip(n);
242 25225x if(! ss)
243 12x return w.suspend(writer::state::str2);
244 }
245 }
246 else
247 {
248 44x if(w.buf_[2] == false)
249 44x ss.append('\x22'); // '"'
250 44x return true;
251 }
252 }
253 else
254 {
255 270x return w.suspend(writer::state::str2);
256 }
257
258 // slow loop,
259 // handle escapes
260 43907x do_str3:
261 31461678x while(BOOST_JSON_LIKELY(ss))
262 {
263 31452552x if(BOOST_JSON_LIKELY(cs))
264 {
265 31417967x auto const ch = *cs;
266 31417967x auto const c = esc[static_cast<
267 unsigned char>(ch)];
268 31417967x ++cs;
269 31417967x if(! c)
270 {
271 31417239x ss.append(ch);
272 }
273 728x else if(c != 'u')
274 {
275 376x ss.append('\\');
276 376x if(BOOST_JSON_LIKELY(ss))
277 {
278 324x ss.append(c);
279 }
280 else
281 {
282 52x w.buf_[0] = c;
283 52x return w.suspend(
284 52x writer::state::esc1);
285 }
286 }
287 else
288 {
289 352x if(BOOST_JSON_LIKELY(
290 ss.remain() >= 6))
291 {
292 208x ss.append("\\u00", 4);
293 208x ss.append(hex[static_cast<
294 208x unsigned char>(ch) >> 4]);
295 208x ss.append(hex[static_cast<
296 208x unsigned char>(ch) & 15]);
297 }
298 else
299 {
300 144x ss.append('\\');
301 144x w.buf_[0] = hex[static_cast<
302 144x unsigned char>(ch) >> 4];
303 144x w.buf_[1] = hex[static_cast<
304 144x unsigned char>(ch) & 15];
305 144x goto do_utf1;
306 }
307 }
308 }
309 else
310 {
311 34585x if(w.buf_[2] == false)
312 {
313 34585x ss.append('\x22'); // '"'
314 }
315 34585x return true;
316 }
317 }
318 9126x return w.suspend(writer::state::str3);
319
320 52x do_esc1:
321 52x BOOST_ASSERT(ss);
322 52x ss.append(w.buf_[0]);
323 52x goto do_str3;
324
325 192x do_utf1:
326 192x if(BOOST_JSON_LIKELY(ss))
327 144x ss.append('u');
328 else
329 48x return w.suspend(writer::state::utf1);
330 192x do_utf2:
331 192x if(BOOST_JSON_LIKELY(ss))
332 144x ss.append('0');
333 else
334 48x return w.suspend(writer::state::utf2);
335 192x do_utf3:
336 192x if(BOOST_JSON_LIKELY(ss))
337 144x ss.append('0');
338 else
339 48x return w.suspend(writer::state::utf3);
340 192x do_utf4:
341 192x if(BOOST_JSON_LIKELY(ss))
342 144x ss.append(w.buf_[0]);
343 else
344 48x return w.suspend(writer::state::utf4);
345 192x do_utf5:
346 192x if(BOOST_JSON_LIKELY(ss))
347 144x ss.append(w.buf_[1]);
348 else
349 48x return w.suspend(writer::state::utf5);
350 144x goto do_str3;
351 44511x }
352
353 bool
354 19881x write_string(writer& w, stream& ss0)
355 {
356 19881x return do_write_string<true>(w, ss0);
357 }
358
359 bool
360 420x resume_string(writer& w, stream& ss0)
361 {
362 420x return do_write_string<false>(w, ss0);
363 }
364
365 template<bool StackEmpty>
366 bool
367 write_value(writer& w, stream& ss);
368
369 template< class T, bool StackEmpty >
370 BOOST_FORCEINLINE
371 bool
372 write_impl(no_conversion_tag, writer& w, stream& ss)
373 {
374 34676x return write_value<StackEmpty>(w, ss);
375 }
376
377 template<bool StackEmpty>
378 bool
379 6088x write_array(writer& w, stream& ss)
380 {
381 6087x return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
382 }
383
384 template<bool StackEmpty>
385 bool
386 27265x write_object(writer& w, stream& ss)
387 {
388 27265x return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
389 }
390
391 template<bool StackEmpty>
392 bool
393 67205x write_value(writer& w, stream& ss)
394 {
395 23064x if(StackEmpty || w.st_.empty())
396 {
397 44651x BOOST_ASSERT( w.p_ );
398 44651x auto const pv = reinterpret_cast<value const*>(w.p_);
399 44651x switch(pv->kind())
400 {
401 18110x default:
402 case kind::object:
403 18110x w.p_ = &pv->get_object();
404 18110x return write_object<true>(w, ss);
405
406 3419x case kind::array:
407 3419x w.p_ = &pv->get_array();
408 3419x return write_array<true>(w, ss);
409
410 14745x case kind::string:
411 {
412 14745x auto const& js = pv->get_string();
413 14745x w.cs0_ = { js.data(), js.size() };
414 14745x w.buf_[2] = js.is_seamless();
415 14745x return do_write_string<true>(w, ss);
416 }
417
418 3182x case kind::int64:
419 3182x return write_int64( w, ss, pv->get_int64() );
420 91x case kind::uint64:
421 91x return write_uint64( w, ss, pv->get_uint64() );
422 467x case kind::double_:
423 467x return write_double( w, ss, pv->get_double() );
424
425 306x case kind::bool_:
426 306x if( pv->get_bool() )
427 139x return write_true(w, ss);
428 else
429 167x return write_false(w, ss);
430
431 4331x case kind::null:
432 4331x return write_null(w, ss);
433 }
434 }
435 else
436 {
437 writer::state st;
438 22554x w.st_.peek(st);
439 22554x switch(st)
440 {
441 1324x default:
442 case writer::state::lit:
443 1324x return resume_buffer(w, ss);
444
445 9462x case writer::state::str1: case writer::state::str2:
446 case writer::state::str3: case writer::state::esc1:
447 case writer::state::utf1: case writer::state::utf2:
448 case writer::state::utf3: case writer::state::utf4:
449 case writer::state::utf5:
450 9462x return do_write_string<false>(w, ss);
451
452 2664x case writer::state::arr1: case writer::state::arr2:
453 case writer::state::arr3: case writer::state::arr4:
454 2664x return write_array<StackEmpty>(w, ss);
455
456 9104x case writer::state::obj1: case writer::state::obj2:
457 case writer::state::obj3: case writer::state::obj4:
458 case writer::state::obj5: case writer::state::obj6:
459 9104x return write_object<StackEmpty>(w, ss);
460 }
461 }
462 }
463
464 } // namespace detail
465
466 2395x serializer::
467 2395x serializer(serialize_options const& opts) noexcept
468 2395x : serializer({}, nullptr, 0, opts)
469 2395x {}
470
471 21301x serializer::
472 serializer(
473 storage_ptr sp,
474 unsigned char* buf,
475 std::size_t buf_size,
476 21301x serialize_options const& opts) noexcept
477 21301x : detail::writer(std::move(sp), buf, buf_size, opts)
478 21301x {}
479
480 void
481 21017x serializer::
482 reset(value const* p) noexcept
483 {
484 21017x p_ = p;
485 21017x fn0_ = &detail::write_value<true>;
486 21017x fn1_ = &detail::write_value<false>;
487 21017x st_.clear();
488 21017x done_ = false;
489 21017x }
490
491 void
492 5x serializer::
493 reset(array const* p) noexcept
494 {
495 5x p_ = p;
496 5x fn0_ = &detail::write_array<true>;
497 5x fn1_ = &detail::write_array<false>;
498 5x st_.clear();
499 5x done_ = false;
500 5x }
501
502 void
503 51x serializer::
504 reset(object const* p) noexcept
505 {
506 51x p_ = p;
507 51x fn0_ = &detail::write_object<true>;
508 51x fn1_ = &detail::write_object<false>;
509 51x st_.clear();
510 51x done_ = false;
511 51x }
512
513 void
514 2x serializer::
515 reset(string const* p) noexcept
516 {
517 2x cs0_ = { p->data(), p->size() };
518 2x buf_[2] = p->is_seamless();
519 2x fn0_ = &detail::do_write_string<true>;
520 2x fn1_ = &detail::do_write_string<false>;
521 2x st_.clear();
522 2x done_ = false;
523 2x }
524
525 void
526 1x serializer::
527 reset(string_view sv) noexcept
528 {
529 1x cs0_ = { sv.data(), sv.size() };
530 1x buf_[2] = false;
531 1x fn0_ = &detail::do_write_string<true>;
532 1x fn1_ = &detail::do_write_string<false>;
533 1x st_.clear();
534 1x done_ = false;
535 1x }
536
537 void
538 6x serializer::reset(std::nullptr_t) noexcept
539 {
540 6x p_ = nullptr;
541 6x fn0_ = &detail::write_impl<std::nullptr_t, true>;
542 6x fn1_ = &detail::write_impl<std::nullptr_t, false>;
543 6x st_.clear();
544 6x done_ = false;
545 6x }
546
547 string_view
548 33121x serializer::
549 read(char* dest, std::size_t size)
550 {
551 33121x if( !fn0_ )
552 6x reset(nullptr);
553
554 33121x if(BOOST_JSON_UNLIKELY(size == 0))
555 1x return {dest, 0};
556
557 33120x detail::stream ss(dest, size);
558 33120x if(st_.empty())
559 21300x fn0_(*this, ss);
560 else
561 11820x fn1_(*this, ss);
562 33118x if(st_.empty())
563 {
564 21298x done_ = true;
565 21298x fn0_ = nullptr;
566 21298x p_ = nullptr;
567 }
568 33118x return string_view(
569 33118x dest, ss.used(dest));
570 }
571
572 } // namespace json
573 } // namespace boost
574
575 #ifdef _MSC_VER
576 #pragma warning(pop)
577 #endif
578
579 #endif
580