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