serializer.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. //
  2. // Copyright (c) 2024 Dmitry Arkhipov (grisumbras@yandex.ru)
  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_HPP
  10. #define BOOST_JSON_IMPL_SERIALIZER_HPP
  11. #include <boost/core/detail/static_assert.hpp>
  12. #include <boost/describe/enum_to_string.hpp>
  13. #include <boost/json/conversion.hpp>
  14. #include <cstddef>
  15. namespace boost {
  16. namespace json {
  17. namespace detail {
  18. enum class writer::state : char
  19. {
  20. str1, str2, str3, esc1, utf1,
  21. utf2, utf3, utf4, utf5,
  22. lit,
  23. arr1, arr2, arr3, arr4,
  24. obj1, obj2, obj3, obj4, obj5, obj6
  25. };
  26. bool
  27. writer::
  28. suspend(state st)
  29. {
  30. st_.push(st);
  31. return false;
  32. }
  33. template<class U, class T>
  34. bool
  35. writer::
  36. suspend(state st, U u, T const* pt)
  37. {
  38. st_.push(pt);
  39. st_.push(u);
  40. st_.push(st);
  41. return false;
  42. }
  43. template<class T, bool StackEmpty>
  44. bool
  45. write_impl(writer& w, stream& ss);
  46. template<class T, bool StackEmpty>
  47. BOOST_FORCEINLINE
  48. bool
  49. write_impl(null_like_conversion_tag, writer& w, stream& ss)
  50. {
  51. #if defined(_MSC_VER)
  52. # pragma warning( push )
  53. # pragma warning( disable : 4127 )
  54. #endif
  55. if( StackEmpty || w.st_.empty() )
  56. return write_null(w, ss);
  57. #if defined(_MSC_VER)
  58. # pragma warning( pop )
  59. #endif
  60. return resume_buffer(w, ss);
  61. }
  62. template<class T, bool StackEmpty>
  63. BOOST_FORCEINLINE
  64. bool
  65. write_impl(bool_conversion_tag, writer& w, stream& ss)
  66. {
  67. BOOST_ASSERT( w.p_ );
  68. auto const t = *reinterpret_cast<T const*>(w.p_);
  69. #if defined(_MSC_VER)
  70. # pragma warning( push )
  71. # pragma warning( disable : 4127 )
  72. #endif
  73. if( StackEmpty || w.st_.empty() )
  74. #if defined(_MSC_VER)
  75. # pragma warning( pop )
  76. #endif
  77. {
  78. if( t )
  79. return write_true(w, ss);
  80. else
  81. return write_false(w, ss);
  82. }
  83. return resume_buffer(w, ss);
  84. }
  85. template<class T, bool StackEmpty>
  86. BOOST_FORCEINLINE
  87. bool
  88. write_impl(integral_conversion_tag, writer& w, stream& ss0)
  89. {
  90. #if defined(_MSC_VER)
  91. # pragma warning( push )
  92. # pragma warning( disable : 4127 )
  93. #endif
  94. if( StackEmpty || w.st_.empty() )
  95. #if defined(_MSC_VER)
  96. # pragma warning( pop )
  97. #endif
  98. {
  99. auto const& t = *reinterpret_cast<T const*>(w.p_);
  100. #if defined(__clang__)
  101. # pragma clang diagnostic push
  102. # pragma clang diagnostic ignored "-Wsign-compare"
  103. #elif defined(__GNUC__)
  104. # pragma GCC diagnostic push
  105. # pragma GCC diagnostic ignored "-Wsign-compare"
  106. #elif defined(_MSC_VER)
  107. # pragma warning( push )
  108. # pragma warning( disable : 4018 )
  109. # pragma warning( disable : 4127 )
  110. #endif
  111. if( t < 0 )
  112. {
  113. // T is obviously signed, so this comparison is safe
  114. if( t >= (std::numeric_limits<std::int64_t>::min)() )
  115. {
  116. std::int64_t i = t;
  117. return write_int64(w, ss0, i);
  118. }
  119. }
  120. else if( t <= (std::numeric_limits<std::uint64_t>::max)() )
  121. {
  122. std::uint64_t u = t;
  123. return write_uint64(w, ss0, u);
  124. }
  125. #if defined(__clang__)
  126. # pragma clang diagnostic pop
  127. #elif defined(__GNUC__)
  128. # pragma GCC diagnostic pop
  129. #elif defined(_MSC_VER)
  130. # pragma warning( pop )
  131. #endif
  132. #if defined(_MSC_VER)
  133. # pragma warning( push )
  134. # pragma warning( disable : 4244 )
  135. #endif
  136. double d = t;
  137. return write_double(w, ss0, d);
  138. #if defined(_MSC_VER)
  139. # pragma warning( pop )
  140. #endif
  141. }
  142. return resume_buffer(w, ss0);
  143. }
  144. template<class T, bool StackEmpty>
  145. BOOST_FORCEINLINE
  146. bool
  147. write_impl(floating_point_conversion_tag, writer& w, stream& ss0)
  148. {
  149. #if defined(_MSC_VER)
  150. # pragma warning( push )
  151. # pragma warning( disable : 4127 )
  152. #endif
  153. if( StackEmpty || w.st_.empty() )
  154. #if defined(_MSC_VER)
  155. # pragma warning( pop )
  156. #endif
  157. {
  158. double d = *reinterpret_cast<T const*>(w.p_);
  159. return write_double(w, ss0, d);
  160. }
  161. return resume_buffer(w, ss0);
  162. }
  163. template<class T, bool StackEmpty>
  164. BOOST_FORCEINLINE
  165. bool
  166. write_impl(string_like_conversion_tag, writer& w, stream& ss0)
  167. {
  168. #if defined(_MSC_VER)
  169. # pragma warning( push )
  170. # pragma warning( disable : 4127 )
  171. #endif
  172. if( StackEmpty || w.st_.empty() )
  173. #if defined(_MSC_VER)
  174. # pragma warning( pop )
  175. #endif
  176. {
  177. string_view const sv = *reinterpret_cast<T const*>(w.p_);
  178. w.cs0_ = { sv.data(), sv.size() };
  179. return write_string(w, ss0);
  180. }
  181. return resume_string(w, ss0);
  182. }
  183. template<class T, bool StackEmpty>
  184. BOOST_FORCEINLINE
  185. bool
  186. write_impl(sequence_conversion_tag, writer& w, stream& ss0)
  187. {
  188. using It = iterator_type<T const>;
  189. using Elem = value_type<T>;
  190. T const* pt;
  191. local_stream ss(ss0);
  192. It it;
  193. It end;
  194. #if defined(_MSC_VER)
  195. # pragma warning( push )
  196. # pragma warning( disable : 4127 )
  197. #endif
  198. if(StackEmpty || w.st_.empty())
  199. {
  200. #if defined(_MSC_VER)
  201. # pragma warning( pop )
  202. #endif
  203. BOOST_ASSERT( w.p_ );
  204. pt = reinterpret_cast<T const*>(w.p_);
  205. it = std::begin(*pt);
  206. end = std::end(*pt);
  207. }
  208. else
  209. {
  210. writer::state st;
  211. w.st_.pop(st);
  212. w.st_.pop(it);
  213. w.st_.pop(pt);
  214. end = std::end(*pt);
  215. switch(st)
  216. {
  217. default:
  218. case writer::state::arr1: goto do_arr1;
  219. case writer::state::arr2: goto do_arr2;
  220. case writer::state::arr3: goto do_arr3;
  221. case writer::state::arr4: goto do_arr4;
  222. break;
  223. }
  224. }
  225. do_arr1:
  226. if(BOOST_JSON_LIKELY(ss))
  227. ss.append('[');
  228. else
  229. return w.suspend(writer::state::arr1, it, pt);
  230. if(it == end)
  231. goto do_arr4;
  232. for(;;)
  233. {
  234. w.p_ = std::addressof(*it);
  235. do_arr2:
  236. if( !write_impl<Elem, StackEmpty>(w, ss) )
  237. return w.suspend(writer::state::arr2, it, pt);
  238. if(BOOST_JSON_UNLIKELY( ++it == end ))
  239. break;
  240. do_arr3:
  241. if(BOOST_JSON_LIKELY(ss))
  242. ss.append(',');
  243. else
  244. return w.suspend(writer::state::arr3, it, pt);
  245. }
  246. do_arr4:
  247. if(BOOST_JSON_LIKELY(ss))
  248. ss.append(']');
  249. else
  250. return w.suspend(writer::state::arr4, it, pt);
  251. return true;
  252. }
  253. template<class T, bool StackEmpty>
  254. BOOST_FORCEINLINE
  255. bool
  256. write_impl(map_like_conversion_tag, writer& w, stream& ss0)
  257. {
  258. using It = iterator_type<T const>;
  259. using Mapped = mapped_type<T>;
  260. T const* pt;
  261. local_stream ss(ss0);
  262. It it;
  263. It end;
  264. #if defined(_MSC_VER)
  265. # pragma warning( push )
  266. # pragma warning( disable : 4127 )
  267. #endif
  268. if(StackEmpty || w.st_.empty())
  269. #if defined(_MSC_VER)
  270. # pragma warning( pop )
  271. #endif
  272. {
  273. BOOST_ASSERT( w.p_ );
  274. pt = reinterpret_cast<T const*>(w.p_);
  275. it = std::begin(*pt);
  276. end = std::end(*pt);
  277. }
  278. else
  279. {
  280. writer::state st;
  281. w.st_.pop(st);
  282. w.st_.pop(it);
  283. w.st_.pop(pt);
  284. end = std::end(*pt);
  285. switch(st)
  286. {
  287. default:
  288. case writer::state::obj1: goto do_obj1;
  289. case writer::state::obj2: goto do_obj2;
  290. case writer::state::obj3: goto do_obj3;
  291. case writer::state::obj4: goto do_obj4;
  292. case writer::state::obj5: goto do_obj5;
  293. case writer::state::obj6: goto do_obj6;
  294. break;
  295. }
  296. }
  297. do_obj1:
  298. if(BOOST_JSON_LIKELY( ss ))
  299. ss.append('{');
  300. else
  301. return w.suspend(writer::state::obj1, it, pt);
  302. if(BOOST_JSON_UNLIKELY( it == end ))
  303. goto do_obj6;
  304. for(;;)
  305. {
  306. {
  307. using std::get;
  308. string_view const sv = get<0>(*it);
  309. w.cs0_ = { sv.data(), sv.size() };
  310. }
  311. if( true )
  312. {
  313. if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
  314. return w.suspend(writer::state::obj2, it, pt);
  315. }
  316. else
  317. {
  318. do_obj2:
  319. if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
  320. return w.suspend(writer::state::obj2, it, pt);
  321. }
  322. do_obj3:
  323. if(BOOST_JSON_LIKELY(ss))
  324. ss.append(':');
  325. else
  326. return w.suspend(writer::state::obj3, it, pt);
  327. do_obj4:
  328. {
  329. using std::get;
  330. w.p_ = std::addressof( get<1>(*it) );
  331. }
  332. if(BOOST_JSON_UNLIKELY(( !write_impl<Mapped, StackEmpty>(w, ss) )))
  333. return w.suspend(writer::state::obj4, it, pt);
  334. ++it;
  335. if(BOOST_JSON_UNLIKELY(it == end))
  336. break;
  337. do_obj5:
  338. if(BOOST_JSON_LIKELY(ss))
  339. ss.append(',');
  340. else
  341. return w.suspend(writer::state::obj5, it, pt);
  342. }
  343. do_obj6:
  344. if(BOOST_JSON_LIKELY( ss ))
  345. {
  346. ss.append('}');
  347. return true;
  348. }
  349. return w.suspend(writer::state::obj6, it, pt);
  350. }
  351. template< class T, bool StackEmpty >
  352. struct serialize_tuple_elem_helper
  353. {
  354. writer& w;
  355. stream& ss;
  356. T const* pt;
  357. template< std::size_t I >
  358. bool
  359. operator()( std::integral_constant<std::size_t, I> ) const
  360. {
  361. using std::get;
  362. w.p_ = std::addressof( get<I>(*pt) );
  363. using Elem = tuple_element_t<I, T>;
  364. return write_impl<Elem, StackEmpty>(w, ss);
  365. }
  366. };
  367. template<class T, bool StackEmpty>
  368. BOOST_FORCEINLINE
  369. bool
  370. write_impl(tuple_conversion_tag, writer& w, stream& ss0)
  371. {
  372. T const* pt;
  373. local_stream ss(ss0);
  374. std::size_t cur;
  375. constexpr std::size_t N = std::tuple_size<T>::value;
  376. #if defined(_MSC_VER)
  377. # pragma warning( push )
  378. # pragma warning( disable : 4127 )
  379. #endif
  380. if(StackEmpty || w.st_.empty())
  381. {
  382. #if defined(_MSC_VER)
  383. # pragma warning( pop )
  384. #endif
  385. BOOST_ASSERT( w.p_ );
  386. pt = reinterpret_cast<T const*>(w.p_);
  387. cur = 0;
  388. }
  389. else
  390. {
  391. writer::state st;
  392. w.st_.pop(st);
  393. w.st_.pop(cur);
  394. w.st_.pop(pt);
  395. switch(st)
  396. {
  397. default:
  398. case writer::state::arr1: goto do_arr1;
  399. case writer::state::arr2: goto do_arr2;
  400. case writer::state::arr3: goto do_arr3;
  401. case writer::state::arr4: goto do_arr4;
  402. break;
  403. }
  404. }
  405. do_arr1:
  406. if(BOOST_JSON_LIKELY(ss))
  407. ss.append('[');
  408. else
  409. return w.suspend(writer::state::arr1, cur, pt);
  410. for(;;)
  411. {
  412. do_arr2:
  413. {
  414. bool const stop = !mp11::mp_with_index<N>(
  415. cur,
  416. serialize_tuple_elem_helper<T, StackEmpty>{w, ss, pt});
  417. if(BOOST_JSON_UNLIKELY( stop ))
  418. return w.suspend(writer::state::arr2, cur, pt);
  419. }
  420. if(BOOST_JSON_UNLIKELY( ++cur == N ))
  421. break;
  422. do_arr3:
  423. if(BOOST_JSON_LIKELY(ss))
  424. ss.append(',');
  425. else
  426. return w.suspend(writer::state::arr3, cur, pt);
  427. }
  428. do_arr4:
  429. if(BOOST_JSON_LIKELY(ss))
  430. ss.append(']');
  431. else
  432. return w.suspend(writer::state::arr4, cur, pt);
  433. return true;
  434. }
  435. template< class T, bool StackEmpty >
  436. struct serialize_struct_elem_helper
  437. {
  438. static_assert(
  439. uniquely_named_members<T>::value,
  440. "The type has several described members with the same name.");
  441. writer& w;
  442. local_stream& ss;
  443. T const* pt;
  444. writer::state st;
  445. template< std::size_t I >
  446. writer::state
  447. operator()( std::integral_constant<std::size_t, I> ) const
  448. {
  449. using Ds = described_members<T>;
  450. using D = mp11::mp_at_c<Ds, I>;
  451. using M = described_member_t<T, D>;
  452. switch(st)
  453. {
  454. case writer::state::obj2: goto do_obj2;
  455. case writer::state::obj3: goto do_obj3;
  456. case writer::state::obj4: goto do_obj4;
  457. default: break;
  458. }
  459. {
  460. string_view const sv = D::name;
  461. w.cs0_ = { sv.data(), sv.size() };
  462. }
  463. if( true )
  464. {
  465. if(BOOST_JSON_UNLIKELY( !write_string(w, ss) ))
  466. return writer::state::obj2;
  467. }
  468. else
  469. {
  470. do_obj2:
  471. if(BOOST_JSON_UNLIKELY( !resume_string(w, ss) ))
  472. return writer::state::obj2;
  473. }
  474. do_obj3:
  475. if(BOOST_JSON_LIKELY(ss))
  476. ss.append(':');
  477. else
  478. return writer::state::obj3;
  479. do_obj4:
  480. w.p_ = std::addressof( pt->* D::pointer );
  481. if(BOOST_JSON_UNLIKELY((
  482. !write_impl<M, StackEmpty>(w, ss) )))
  483. return writer::state::obj4;
  484. return writer::state{};
  485. }
  486. };
  487. template<class T, bool StackEmpty>
  488. BOOST_FORCEINLINE
  489. bool
  490. write_impl(described_class_conversion_tag, writer& w, stream& ss0)
  491. {
  492. using Ds = described_members<T>;
  493. T const* pt;
  494. local_stream ss(ss0);
  495. std::size_t cur;
  496. constexpr std::size_t N = mp11::mp_size<Ds>::value;
  497. writer::state st;
  498. #if defined(_MSC_VER)
  499. # pragma warning( push )
  500. # pragma warning( disable : 4127 )
  501. #endif
  502. if(StackEmpty || w.st_.empty())
  503. #if defined(_MSC_VER)
  504. # pragma warning( pop )
  505. #endif
  506. {
  507. BOOST_ASSERT( w.p_ );
  508. pt = reinterpret_cast<T const*>(w.p_);
  509. cur = 0;
  510. }
  511. else
  512. {
  513. w.st_.pop(st);
  514. w.st_.pop(cur);
  515. w.st_.pop(pt);
  516. switch(st)
  517. {
  518. default:
  519. case writer::state::obj1: goto do_obj1;
  520. case writer::state::obj2: // fall through
  521. case writer::state::obj3: // fall through
  522. case writer::state::obj4: goto do_obj2;
  523. case writer::state::obj5: goto do_obj5;
  524. case writer::state::obj6: goto do_obj6;
  525. break;
  526. }
  527. }
  528. do_obj1:
  529. if(BOOST_JSON_LIKELY( ss ))
  530. ss.append('{');
  531. else
  532. return w.suspend(writer::state::obj1, cur, pt);
  533. if(BOOST_JSON_UNLIKELY( cur == N ))
  534. goto do_obj6;
  535. for(;;)
  536. {
  537. st = {};
  538. do_obj2:
  539. st = mp11::mp_with_index<N>(
  540. cur,
  541. serialize_struct_elem_helper<T, StackEmpty>{w, ss, pt, st});
  542. if(BOOST_JSON_UNLIKELY( st != writer::state{} ))
  543. return w.suspend(st, cur, pt);
  544. ++cur;
  545. if(BOOST_JSON_UNLIKELY(cur == N))
  546. break;
  547. do_obj5:
  548. if(BOOST_JSON_LIKELY(ss))
  549. ss.append(',');
  550. else
  551. return w.suspend(writer::state::obj5, cur, pt);
  552. }
  553. do_obj6:
  554. if(BOOST_JSON_LIKELY( ss ))
  555. {
  556. ss.append('}');
  557. return true;
  558. }
  559. return w.suspend(writer::state::obj6, cur, pt);
  560. }
  561. template<class T, bool StackEmpty>
  562. BOOST_FORCEINLINE
  563. bool
  564. write_impl(described_enum_conversion_tag, writer& w, stream& ss)
  565. {
  566. #ifdef BOOST_DESCRIBE_CXX14
  567. using Integer = typename std::underlying_type<T>::type;
  568. #if defined(_MSC_VER)
  569. # pragma warning( push )
  570. # pragma warning( disable : 4127 )
  571. #endif
  572. if(StackEmpty || w.st_.empty())
  573. #if defined(_MSC_VER)
  574. # pragma warning( pop )
  575. #endif
  576. {
  577. BOOST_ASSERT( w.p_ );
  578. T const* pt = reinterpret_cast<T const*>(w.p_);
  579. char const* const name = describe::enum_to_string(*pt, nullptr);
  580. if( name )
  581. {
  582. string_view const sv = name;
  583. w.cs0_ = { sv.data(), sv.size() };
  584. return write_string(w, ss);
  585. }
  586. else
  587. {
  588. Integer n = static_cast<Integer>(*pt);
  589. w.p_ = &n;
  590. return write_impl<Integer, true>(w, ss);
  591. }
  592. }
  593. else
  594. {
  595. writer::state st;
  596. w.st_.peek(st);
  597. if( st == writer::state::lit )
  598. return write_impl<Integer, false>(w, ss);
  599. else
  600. return resume_string(w, ss);
  601. }
  602. #else // BOOST_DESCRIBE_CXX14
  603. (void)w;
  604. (void)ss;
  605. static_assert(
  606. !std::is_same<T, T>::value,
  607. "described enums require C++14 support");
  608. return false;
  609. #endif // BOOST_DESCRIBE_CXX14
  610. }
  611. template< class T, bool StackEmpty >
  612. struct serialize_variant_elem_helper
  613. {
  614. writer& w;
  615. stream& ss;
  616. template<class Elem>
  617. bool
  618. operator()(Elem const& x) const
  619. {
  620. w.p_ = std::addressof(x);
  621. return write_impl<Elem, true>(w, ss);
  622. }
  623. };
  624. template< class T >
  625. struct serialize_variant_elem_helper<T, false>
  626. {
  627. writer& w;
  628. stream& ss;
  629. template< std::size_t I >
  630. bool
  631. operator()( std::integral_constant<std::size_t, I> ) const
  632. {
  633. using std::get;
  634. using Elem = remove_cvref<decltype(get<I>(
  635. std::declval<T const&>() ))>;
  636. return write_impl<Elem, false>(w, ss);
  637. }
  638. };
  639. template<class T, bool StackEmpty>
  640. BOOST_FORCEINLINE
  641. bool
  642. write_impl(variant_conversion_tag, writer& w, stream& ss)
  643. {
  644. T const* pt;
  645. using Index = remove_cvref<decltype( pt->index() )>;
  646. #if defined(_MSC_VER)
  647. # pragma warning( push )
  648. # pragma warning( disable : 4127 )
  649. #endif
  650. if(StackEmpty || w.st_.empty())
  651. #if defined(_MSC_VER)
  652. # pragma warning( pop )
  653. #endif
  654. {
  655. BOOST_ASSERT( w.p_ );
  656. pt = reinterpret_cast<T const*>(w.p_);
  657. if(BOOST_JSON_LIKELY((
  658. visit(serialize_variant_elem_helper<T, true>{w, ss}, *pt))))
  659. return true;
  660. Index const ix = pt->index();
  661. w.st_.push(ix);
  662. return false;
  663. }
  664. else
  665. {
  666. Index ix;
  667. w.st_.pop(ix);
  668. constexpr std::size_t N = mp11::mp_size<T>::value;
  669. if(BOOST_JSON_LIKELY(( mp11::mp_with_index<N>(
  670. ix,
  671. serialize_variant_elem_helper<T, false>{w, ss}))))
  672. return true;
  673. w.st_.push(ix);
  674. return false;
  675. }
  676. }
  677. template<class T, bool StackEmpty>
  678. BOOST_FORCEINLINE
  679. bool
  680. write_impl(optional_conversion_tag, writer& w, stream& ss)
  681. {
  682. using Elem = value_result_type<T>;
  683. bool done;
  684. bool has_value;
  685. #if defined(_MSC_VER)
  686. # pragma warning( push )
  687. # pragma warning( disable : 4127 )
  688. #endif
  689. if(StackEmpty || w.st_.empty())
  690. #if defined(_MSC_VER)
  691. # pragma warning( pop )
  692. #endif
  693. {
  694. BOOST_ASSERT( w.p_ );
  695. T const* pt = reinterpret_cast<T const*>(w.p_);
  696. has_value = static_cast<bool>(*pt);
  697. if( has_value )
  698. {
  699. w.p_ = std::addressof( *(*pt) );
  700. done = write_impl<Elem, true>(w, ss);
  701. }
  702. else
  703. {
  704. w.p_ = nullptr;
  705. done = write_impl<std::nullptr_t, true>(w, ss);;
  706. }
  707. }
  708. else
  709. {
  710. w.st_.pop(has_value);
  711. if( has_value )
  712. done = write_impl<Elem, false>(w, ss);
  713. else
  714. done = write_impl<std::nullptr_t, false>(w, ss);
  715. }
  716. if(BOOST_JSON_UNLIKELY( !done ))
  717. w.st_.push(has_value);
  718. return done;
  719. }
  720. template<class T, bool StackEmpty>
  721. BOOST_FORCEINLINE
  722. bool
  723. write_impl(path_conversion_tag, writer& w, stream& ss)
  724. {
  725. #if defined(_MSC_VER)
  726. # pragma warning( push )
  727. # pragma warning( disable : 4127 )
  728. #endif
  729. if(StackEmpty || w.st_.empty())
  730. #if defined(_MSC_VER)
  731. # pragma warning( pop )
  732. #endif
  733. {
  734. BOOST_ASSERT( w.p_ );
  735. T const* pt = reinterpret_cast<T const*>(w.p_);
  736. std::string const s = pt->generic_string();
  737. w.cs0_ = { s.data(), s.size() };
  738. if(BOOST_JSON_LIKELY( write_string(w, ss) ))
  739. return true;
  740. std::size_t const used = w.cs0_.used( s.data() );
  741. w.st_.push( used );
  742. w.st_.push( std::move(s) );
  743. return false;
  744. }
  745. else
  746. {
  747. std::string s;
  748. std::size_t used;
  749. w.st_.pop( s );
  750. w.st_.pop( used );
  751. w.cs0_ = { s.data(), s.size() };
  752. w.cs0_.skip(used);
  753. if(BOOST_JSON_LIKELY( resume_string(w, ss) ))
  754. return true;
  755. used = w.cs0_.used( s.data() );
  756. w.st_.push( used );
  757. w.st_.push( std::move(s) );
  758. return false;
  759. }
  760. }
  761. template<class T, bool StackEmpty>
  762. bool
  763. write_impl(writer& w, stream& ss)
  764. {
  765. using cat = detail::generic_conversion_category<T>;
  766. return write_impl<T, StackEmpty>( cat(), w, ss );
  767. }
  768. } // namespace detail
  769. template<class T>
  770. void
  771. serializer::reset(T const* p) noexcept
  772. {
  773. BOOST_CORE_STATIC_ASSERT( !std::is_pointer<T>::value );
  774. BOOST_CORE_STATIC_ASSERT( std::is_object<T>::value );
  775. p_ = p;
  776. fn0_ = &detail::write_impl<T, true>;
  777. fn1_ = &detail::write_impl<T, false>;
  778. st_.clear();
  779. done_ = false;
  780. }
  781. } // namespace json
  782. } // namespace boost
  783. #endif // BOOST_JSON_IMPL_SERIALIZER_HPP