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