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 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 21245 : writer::
62 : writer(
63 : storage_ptr sp,
64 : unsigned char* buf,
65 : std::size_t buf_size,
66 21245 : serialize_options const& opts) noexcept
67 21245 : : st_(
68 21245 : std::move(sp),
69 : buf,
70 : buf_size)
71 21245 : , opts_(opts)
72 : {
73 : // ensure room for \uXXXX escape plus one
74 : BOOST_CORE_STATIC_ASSERT( sizeof(buf_) >= 7 );
75 21245 : }
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 44285 : do_write_string(writer& w, stream& ss0)
182 : {
183 44285 : local_stream ss(ss0);
184 44285 : local_const_stream cs(w.cs0_);
185 9812 : if(! StackEmpty && ! w.st_.empty())
186 : {
187 : writer::state st;
188 9812 : w.st_.pop(st);
189 9812 : switch(st)
190 : {
191 170 : default:
192 170 : case writer::state::str1: goto do_str1;
193 268 : case writer::state::str2: goto do_str2;
194 9082 : 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 34473 : do_str1:
216 34643 : if(BOOST_JSON_LIKELY(ss))
217 34473 : ss.append('\x22'); // '"'
218 : else
219 170 : return w.suspend(writer::state::str1);
220 :
221 : // fast loop,
222 : // copy unescaped
223 34741 : do_str2:
224 34741 : if(BOOST_JSON_LIKELY(ss))
225 : {
226 34485 : std::size_t n = cs.remain();
227 34485 : if(BOOST_JSON_LIKELY(n > 0))
228 : {
229 34441 : if(ss.remain() > n)
230 25766 : n = detail::count_unescaped(
231 : cs.data(), n);
232 : else
233 8675 : n = detail::count_unescaped(
234 : cs.data(), ss.remain());
235 34441 : if(n > 0)
236 : {
237 25225 : ss.append(cs.data(), n);
238 25225 : cs.skip(n);
239 25225 : if(! ss)
240 12 : return w.suspend(writer::state::str2);
241 : }
242 : }
243 : else
244 : {
245 44 : ss.append('\x22'); // '"'
246 44 : return true;
247 : }
248 : }
249 : else
250 : {
251 256 : return w.suspend(writer::state::str2);
252 : }
253 :
254 : // slow loop,
255 : // handle escapes
256 43707 : do_str3:
257 31461016 : while(BOOST_JSON_LIKELY(ss))
258 : {
259 31451934 : if(BOOST_JSON_LIKELY(cs))
260 : {
261 31417505 : auto const ch = *cs;
262 31417505 : auto const c = esc[static_cast<
263 : unsigned char>(ch)];
264 31417505 : ++cs;
265 31417505 : if(! c)
266 : {
267 31416777 : ss.append(ch);
268 : }
269 728 : else if(c != 'u')
270 : {
271 376 : ss.append('\\');
272 376 : if(BOOST_JSON_LIKELY(ss))
273 : {
274 324 : ss.append(c);
275 : }
276 : else
277 : {
278 52 : w.buf_[0] = c;
279 52 : return w.suspend(
280 52 : writer::state::esc1);
281 : }
282 : }
283 : else
284 : {
285 352 : if(BOOST_JSON_LIKELY(
286 : ss.remain() >= 6))
287 : {
288 208 : ss.append("\\u00", 4);
289 208 : ss.append(hex[static_cast<
290 208 : unsigned char>(ch) >> 4]);
291 208 : ss.append(hex[static_cast<
292 208 : unsigned char>(ch) & 15]);
293 : }
294 : else
295 : {
296 144 : ss.append('\\');
297 144 : w.buf_[0] = hex[static_cast<
298 144 : unsigned char>(ch) >> 4];
299 144 : w.buf_[1] = hex[static_cast<
300 144 : unsigned char>(ch) & 15];
301 144 : goto do_utf1;
302 : }
303 : }
304 : }
305 : else
306 : {
307 34429 : ss.append('\x22'); // '"'
308 34429 : return true;
309 : }
310 : }
311 9082 : return w.suspend(writer::state::str3);
312 :
313 52 : do_esc1:
314 52 : BOOST_ASSERT(ss);
315 52 : ss.append(w.buf_[0]);
316 52 : goto do_str3;
317 :
318 192 : do_utf1:
319 192 : if(BOOST_JSON_LIKELY(ss))
320 144 : ss.append('u');
321 : else
322 48 : return w.suspend(writer::state::utf1);
323 192 : do_utf2:
324 192 : if(BOOST_JSON_LIKELY(ss))
325 144 : ss.append('0');
326 : else
327 48 : return w.suspend(writer::state::utf2);
328 192 : do_utf3:
329 192 : if(BOOST_JSON_LIKELY(ss))
330 144 : ss.append('0');
331 : else
332 48 : return w.suspend(writer::state::utf3);
333 192 : do_utf4:
334 192 : if(BOOST_JSON_LIKELY(ss))
335 144 : ss.append(w.buf_[0]);
336 : else
337 48 : return w.suspend(writer::state::utf4);
338 192 : do_utf5:
339 192 : if(BOOST_JSON_LIKELY(ss))
340 144 : ss.append(w.buf_[1]);
341 : else
342 48 : return w.suspend(writer::state::utf5);
343 144 : goto do_str3;
344 44285 : }
345 :
346 : bool
347 19827 : write_string(writer& w, stream& ss0)
348 : {
349 19827 : return do_write_string<true>(w, ss0);
350 : }
351 :
352 : bool
353 408 : resume_string(writer& w, stream& ss0)
354 : {
355 408 : return do_write_string<false>(w, ss0);
356 : }
357 :
358 : template<bool StackEmpty>
359 : bool
360 : write_value(writer& w, stream& ss);
361 :
362 : template< class T, bool StackEmpty >
363 : BOOST_FORCEINLINE
364 : bool
365 : write_impl(no_conversion_tag, writer& w, stream& ss)
366 : {
367 34536 : return write_value<StackEmpty>(w, ss);
368 : }
369 :
370 : template<bool StackEmpty>
371 : bool
372 6041 : write_array(writer& w, stream& ss)
373 : {
374 6040 : return write_impl<array, StackEmpty>(sequence_conversion_tag(), w, ss);
375 : }
376 :
377 : template<bool StackEmpty>
378 : bool
379 27194 : write_object(writer& w, stream& ss)
380 : {
381 27194 : return write_impl<object, StackEmpty>(map_like_conversion_tag(), w, ss);
382 : }
383 :
384 : template<bool StackEmpty>
385 : bool
386 66927 : write_value(writer& w, stream& ss)
387 : {
388 22905 : if(StackEmpty || w.st_.empty())
389 : {
390 44503 : BOOST_ASSERT( w.p_ );
391 44503 : auto const pv = reinterpret_cast<value const*>(w.p_);
392 44503 : switch(pv->kind())
393 : {
394 18083 : default:
395 : case kind::object:
396 18083 : w.p_ = &pv->get_object();
397 18083 : return write_object<true>(w, ss);
398 :
399 3400 : case kind::array:
400 3400 : w.p_ = &pv->get_array();
401 3400 : return write_array<true>(w, ss);
402 :
403 14643 : case kind::string:
404 : {
405 14643 : auto const& js = pv->get_string();
406 14643 : w.cs0_ = { js.data(), js.size() };
407 14643 : return do_write_string<true>(w, ss);
408 : }
409 :
410 3182 : case kind::int64:
411 3182 : return write_int64( w, ss, pv->get_int64() );
412 91 : case kind::uint64:
413 91 : return write_uint64( w, ss, pv->get_uint64() );
414 467 : case kind::double_:
415 467 : return write_double( w, ss, pv->get_double() );
416 :
417 306 : case kind::bool_:
418 306 : if( pv->get_bool() )
419 139 : return write_true(w, ss);
420 : else
421 167 : return write_false(w, ss);
422 :
423 4331 : case kind::null:
424 4331 : return write_null(w, ss);
425 : }
426 : }
427 : else
428 : {
429 : writer::state st;
430 22424 : w.st_.peek(st);
431 22424 : switch(st)
432 : {
433 1324 : default:
434 : case writer::state::lit:
435 1324 : return resume_buffer(w, ss);
436 :
437 9404 : case writer::state::str1: case writer::state::str2:
438 : case writer::state::str3: case writer::state::esc1:
439 : case writer::state::utf1: case writer::state::utf2:
440 : case writer::state::utf3: case writer::state::utf4:
441 : case writer::state::utf5:
442 9404 : return do_write_string<false>(w, ss);
443 :
444 2636 : case writer::state::arr1: case writer::state::arr2:
445 : case writer::state::arr3: case writer::state::arr4:
446 2636 : return write_array<StackEmpty>(w, ss);
447 :
448 9060 : case writer::state::obj1: case writer::state::obj2:
449 : case writer::state::obj3: case writer::state::obj4:
450 : case writer::state::obj5: case writer::state::obj6:
451 9060 : return write_object<StackEmpty>(w, ss);
452 : }
453 : }
454 : }
455 :
456 : } // namespace detail
457 :
458 2348 : serializer::
459 2348 : serializer(serialize_options const& opts) noexcept
460 2348 : : serializer({}, nullptr, 0, opts)
461 2348 : {}
462 :
463 21245 : serializer::
464 : serializer(
465 : storage_ptr sp,
466 : unsigned char* buf,
467 : std::size_t buf_size,
468 21245 : serialize_options const& opts) noexcept
469 21245 : : detail::writer(std::move(sp), buf, buf_size, opts)
470 21245 : {}
471 :
472 : void
473 20961 : serializer::
474 : reset(value const* p) noexcept
475 : {
476 20961 : p_ = p;
477 20961 : fn0_ = &detail::write_value<true>;
478 20961 : fn1_ = &detail::write_value<false>;
479 20961 : st_.clear();
480 20961 : done_ = false;
481 20961 : }
482 :
483 : void
484 5 : serializer::
485 : reset(array const* p) noexcept
486 : {
487 5 : p_ = p;
488 5 : fn0_ = &detail::write_array<true>;
489 5 : fn1_ = &detail::write_array<false>;
490 5 : st_.clear();
491 5 : done_ = false;
492 5 : }
493 :
494 : void
495 51 : serializer::
496 : reset(object const* p) noexcept
497 : {
498 51 : p_ = p;
499 51 : fn0_ = &detail::write_object<true>;
500 51 : fn1_ = &detail::write_object<false>;
501 51 : st_.clear();
502 51 : done_ = false;
503 51 : }
504 :
505 : void
506 2 : serializer::
507 : reset(string const* p) noexcept
508 : {
509 2 : cs0_ = { p->data(), p->size() };
510 2 : fn0_ = &detail::do_write_string<true>;
511 2 : fn1_ = &detail::do_write_string<false>;
512 2 : st_.clear();
513 2 : done_ = false;
514 2 : }
515 :
516 : void
517 1 : serializer::
518 : reset(string_view sv) noexcept
519 : {
520 1 : cs0_ = { sv.data(), sv.size() };
521 1 : fn0_ = &detail::do_write_string<true>;
522 1 : fn1_ = &detail::do_write_string<false>;
523 1 : st_.clear();
524 1 : done_ = false;
525 1 : }
526 :
527 : void
528 6 : serializer::reset(std::nullptr_t) noexcept
529 : {
530 6 : p_ = nullptr;
531 6 : fn0_ = &detail::write_impl<std::nullptr_t, true>;
532 6 : fn1_ = &detail::write_impl<std::nullptr_t, false>;
533 6 : st_.clear();
534 6 : done_ = false;
535 6 : }
536 :
537 : string_view
538 32983 : serializer::
539 : read(char* dest, std::size_t size)
540 : {
541 32983 : if( !fn0_ )
542 6 : reset(nullptr);
543 :
544 32983 : if(BOOST_JSON_UNLIKELY(size == 0))
545 1 : return {dest, 0};
546 :
547 32982 : detail::stream ss(dest, size);
548 32982 : if(st_.empty())
549 21244 : fn0_(*this, ss);
550 : else
551 11738 : fn1_(*this, ss);
552 32980 : if(st_.empty())
553 : {
554 21242 : done_ = true;
555 21242 : fn0_ = nullptr;
556 21242 : p_ = nullptr;
557 : }
558 32980 : return string_view(
559 32980 : dest, ss.used(dest));
560 : }
561 :
562 : } // namespace json
563 : } // namespace boost
564 :
565 : #ifdef _MSC_VER
566 : #pragma warning(pop)
567 : #endif
568 :
569 : #endif
|