serializer.ipp 13 KB

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