json.hpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. // Copyright (c) 2021-2022 configor - Nomango
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. #pragma once
  21. #include "configor.hpp"
  22. #include <algorithm> // std::for_each
  23. #include <iomanip> // std::setprecision
  24. #include <ios> // std::noskipws, std::noshowbase, std::right
  25. namespace configor
  26. {
  27. namespace detail
  28. {
  29. template <typename _ValTy, typename _SourceCharTy>
  30. class json_parser;
  31. template <typename _ValTy, typename _TargetCharTy>
  32. class json_serializer;
  33. } // namespace detail
  34. template <typename _Args, template <typename> class _DefaultEncoding = encoding::auto_utf>
  35. class basic_json final
  36. : public detail::serializable<_Args, detail::json_serializer, _DefaultEncoding>
  37. , public detail::parsable<_Args, detail::json_parser, _DefaultEncoding>
  38. , public detail::value_maker<basic_value<_Args>>
  39. , public detail::iostream_wrapper_maker<basic_json<_Args, _DefaultEncoding>, basic_value<_Args>>
  40. {
  41. public:
  42. using value = basic_value<_Args>;
  43. using serializer =
  44. typename detail::serializable<_Args, detail::json_serializer,
  45. _DefaultEncoding>::template serializer_type<typename value::char_type>;
  46. using parser = typename detail::parsable<_Args, detail::json_parser,
  47. _DefaultEncoding>::template parser_type<typename value::char_type>;
  48. };
  49. using json = basic_json<value_tplargs>;
  50. using wjson = basic_json<wvalue_tplargs>;
  51. // type traits
  52. template <typename _Ty>
  53. struct is_json : std::false_type
  54. {
  55. };
  56. template <typename _Args, template <typename> class _DefaultEncoding>
  57. struct is_json<basic_json<_Args, _DefaultEncoding>> : std::true_type
  58. {
  59. };
  60. namespace detail
  61. {
  62. template <typename _IntTy>
  63. struct json_hex
  64. {
  65. const _IntTy i;
  66. template <typename _CharTy>
  67. friend inline std::basic_ostream<_CharTy>& operator<<(std::basic_ostream<_CharTy>& os, const json_hex& i)
  68. {
  69. os << std::setfill(_CharTy('0')) << std::hex << std::uppercase;
  70. os << '\\' << 'u' << std::setw(sizeof(i.i)) << i.i;
  71. os << std::dec << std::nouppercase;
  72. return os;
  73. }
  74. };
  75. namespace
  76. {
  77. template <typename _IntTy>
  78. inline json_hex<_IntTy> make_json_hex(const _IntTy i)
  79. {
  80. return json_hex<_IntTy>{ i };
  81. }
  82. } // namespace
  83. //
  84. // json_parser
  85. //
  86. template <typename _ValTy, typename _SourceCharTy>
  87. class json_parser : public basic_parser<_ValTy, _SourceCharTy>
  88. {
  89. public:
  90. using value_type = _ValTy;
  91. using source_char_type = _SourceCharTy;
  92. using target_char_type = typename value_type::char_type;
  93. using option = std::function<void(json_parser&)>;
  94. static option with_error_handler(error_handler* eh)
  95. {
  96. return [=](json_parser& p) { p.set_error_handler(eh); };
  97. }
  98. template <template <class> class _Encoding>
  99. static option with_encoding()
  100. {
  101. return [=](json_parser& p)
  102. {
  103. p.template set_source_encoding<_Encoding>();
  104. p.template set_target_encoding<_Encoding>();
  105. };
  106. }
  107. template <template <class> class _Encoding>
  108. static option with_source_encoding()
  109. {
  110. return [=](json_parser& p) { p.template set_source_encoding<_Encoding>(); };
  111. }
  112. template <template <class> class _Encoding>
  113. static option with_target_encoding()
  114. {
  115. return [=](json_parser& p) { p.template set_target_encoding<_Encoding>(); };
  116. }
  117. explicit json_parser(std::basic_istream<source_char_type>& is)
  118. : basic_parser<value_type, source_char_type>(is)
  119. , is_negative_(false)
  120. , current_(0)
  121. , number_integer_(0)
  122. , number_float_(0)
  123. {
  124. }
  125. inline void prepare(std::initializer_list<option> options)
  126. {
  127. std::for_each(options.begin(), options.end(), [&](const option& option) { option(*this); });
  128. }
  129. virtual void parse(value_type& c) override
  130. {
  131. // read first char
  132. read_next();
  133. basic_parser<value_type, source_char_type>::parse(c);
  134. }
  135. virtual void get_integer(typename value_type::integer_type& out) override
  136. {
  137. out = is_negative_ ? -number_integer_ : number_integer_;
  138. }
  139. virtual void get_float(typename value_type::float_type& out) override
  140. {
  141. out = is_negative_ ? -number_float_ : number_float_;
  142. }
  143. virtual void get_string(typename value_type::string_type& out) override
  144. {
  145. scan_string(out);
  146. }
  147. virtual token_type scan() override
  148. {
  149. skip_spaces();
  150. if (this->is_.eof())
  151. return token_type::end_of_input;
  152. token_type result = token_type::uninitialized;
  153. switch (current_)
  154. {
  155. case '[':
  156. result = token_type::begin_array;
  157. break;
  158. case ']':
  159. result = token_type::end_array;
  160. break;
  161. case '{':
  162. result = token_type::begin_object;
  163. break;
  164. case '}':
  165. result = token_type::end_object;
  166. break;
  167. case ':':
  168. result = token_type::name_separator;
  169. break;
  170. case ',':
  171. result = token_type::value_separator;
  172. break;
  173. case 't':
  174. return scan_literal({ 't', 'r', 'u', 'e' }, token_type::literal_true);
  175. case 'f':
  176. return scan_literal({ 'f', 'a', 'l', 's', 'e' }, token_type::literal_false);
  177. case 'n':
  178. return scan_literal({ 'n', 'u', 'l', 'l' }, token_type::literal_null);
  179. case '\"':
  180. // lazy load
  181. return token_type::value_string;
  182. case '-':
  183. case '+':
  184. case '0':
  185. case '1':
  186. case '2':
  187. case '3':
  188. case '4':
  189. case '5':
  190. case '6':
  191. case '7':
  192. case '8':
  193. case '9':
  194. return scan_number();
  195. case '\0':
  196. return token_type::end_of_input;
  197. default:
  198. {
  199. fail("unexpected character", current_);
  200. }
  201. }
  202. // skip next char
  203. read_next();
  204. return result;
  205. }
  206. uint32_t read_next()
  207. {
  208. if (this->source_decoder_(this->is_, current_))
  209. {
  210. if (!this->is_.good())
  211. {
  212. fail("decoding failed with codepoint", current_);
  213. }
  214. }
  215. else
  216. {
  217. current_ = 0;
  218. }
  219. return current_;
  220. }
  221. void skip_spaces()
  222. {
  223. while (current_ == ' ' || current_ == '\t' || current_ == '\n' || current_ == '\r')
  224. read_next();
  225. // skip comments
  226. if (current_ == '/')
  227. {
  228. skip_comments();
  229. }
  230. }
  231. void skip_comments()
  232. {
  233. read_next();
  234. if (current_ == '/')
  235. {
  236. // one line comment
  237. while (true)
  238. {
  239. read_next();
  240. if (current_ == '\n' || current_ == '\r')
  241. {
  242. // end of comment
  243. skip_spaces();
  244. break;
  245. }
  246. if (this->is_.eof())
  247. {
  248. break;
  249. }
  250. }
  251. }
  252. else if (current_ == '*')
  253. {
  254. // multiple line comment
  255. while (true)
  256. {
  257. if (read_next() == '*')
  258. {
  259. if (read_next() == '/')
  260. {
  261. // end of comment
  262. read_next();
  263. break;
  264. }
  265. }
  266. if (this->is_.eof())
  267. {
  268. fail("unexpected eof while reading comment");
  269. }
  270. }
  271. skip_spaces();
  272. }
  273. else
  274. {
  275. fail("unexpected character '/'");
  276. }
  277. }
  278. token_type scan_literal(std::initializer_list<source_char_type> text, token_type result)
  279. {
  280. for (const auto ch : text)
  281. {
  282. if (ch != std::char_traits<source_char_type>::to_char_type(current_))
  283. {
  284. detail::fast_ostringstream ss;
  285. ss << "unexpected character '" << static_cast<char>(current_) << "'";
  286. ss << " (expected literal '";
  287. for (const auto ch : text)
  288. ss.put(static_cast<char>(ch));
  289. ss << "')";
  290. fail(ss.str());
  291. }
  292. read_next();
  293. }
  294. return result;
  295. }
  296. void scan_string(typename value_type::string_type& out)
  297. {
  298. CONFIGOR_ASSERT(current_ == '\"');
  299. detail::fast_string_ostreambuf<target_char_type> buf{ out };
  300. std::basic_ostream<target_char_type> oss{ &buf };
  301. while (true)
  302. {
  303. read_next();
  304. if (this->is_.eof())
  305. {
  306. fail("unexpected end of string");
  307. }
  308. switch (current_)
  309. {
  310. case '\"':
  311. {
  312. // end of string
  313. // skip last `\"`
  314. read_next();
  315. return;
  316. }
  317. case 0x00:
  318. case 0x01:
  319. case 0x02:
  320. case 0x03:
  321. case 0x04:
  322. case 0x05:
  323. case 0x06:
  324. case 0x07:
  325. case 0x08:
  326. case 0x09:
  327. case 0x0A:
  328. case 0x0B:
  329. case 0x0C:
  330. case 0x0D:
  331. case 0x0E:
  332. case 0x0F:
  333. case 0x10:
  334. case 0x11:
  335. case 0x12:
  336. case 0x13:
  337. case 0x14:
  338. case 0x15:
  339. case 0x16:
  340. case 0x17:
  341. case 0x18:
  342. case 0x19:
  343. case 0x1A:
  344. case 0x1B:
  345. case 0x1C:
  346. case 0x1D:
  347. case 0x1E:
  348. case 0x1F:
  349. {
  350. fail("invalid control character", current_);
  351. }
  352. case '\\':
  353. {
  354. switch (read_next())
  355. {
  356. case '\"':
  357. oss << '\"';
  358. break;
  359. case '\\':
  360. oss << '\\';
  361. break;
  362. case '/':
  363. oss << '/';
  364. break;
  365. case 'b':
  366. oss << '\b';
  367. break;
  368. case 'f':
  369. oss << '\f';
  370. break;
  371. case 'n':
  372. oss << '\n';
  373. break;
  374. case 'r':
  375. oss << '\r';
  376. break;
  377. case 't':
  378. oss << '\t';
  379. break;
  380. case 'u':
  381. {
  382. uint32_t codepoint = read_escaped_codepoint();
  383. if (encoding::unicode::is_lead_surrogate(codepoint))
  384. {
  385. if (read_next() != '\\' || read_next() != 'u')
  386. {
  387. fail("lead surrogate must be followed by trail surrogate, but got", current_);
  388. }
  389. const auto lead_surrogate = codepoint;
  390. const auto trail_surrogate = read_escaped_codepoint();
  391. if (!encoding::unicode::is_trail_surrogate(trail_surrogate))
  392. {
  393. fail("surrogate U+D800...U+DBFF must be followed by U+DC00...U+DFFF, but got",
  394. trail_surrogate);
  395. }
  396. codepoint = encoding::unicode::decode_surrogates(lead_surrogate, trail_surrogate);
  397. }
  398. this->target_encoder_(oss, codepoint);
  399. if (!oss.good())
  400. {
  401. fail("encoding failed with codepoint", codepoint);
  402. }
  403. break;
  404. }
  405. default:
  406. {
  407. fail("invalid escaped character", current_);
  408. }
  409. }
  410. break;
  411. }
  412. default:
  413. {
  414. this->target_encoder_(oss, current_);
  415. if (!oss.good())
  416. {
  417. fail("encoding failed with codepoint", current_);
  418. }
  419. }
  420. }
  421. }
  422. }
  423. token_type scan_number()
  424. {
  425. is_negative_ = false;
  426. number_integer_ = 0;
  427. if (current_ == '-' || current_ == '+')
  428. {
  429. is_negative_ = (current_ == '-');
  430. read_next();
  431. }
  432. if (current_ == '0')
  433. {
  434. read_next();
  435. if (current_ == '.')
  436. return scan_float();
  437. if (current_ == 'e' || current_ == 'E')
  438. fail("invalid exponent");
  439. // zero
  440. return token_type::value_integer;
  441. }
  442. return scan_integer();
  443. }
  444. token_type scan_integer()
  445. {
  446. using integer_type = typename value_type::integer_type;
  447. CONFIGOR_ASSERT(is_digit(current_));
  448. number_integer_ = static_cast<integer_type>(current_ - '0');
  449. while (true)
  450. {
  451. const auto ch = read_next();
  452. if (ch == '.' || ch == 'e' || ch == 'E')
  453. return scan_float();
  454. if (is_digit(ch))
  455. number_integer_ = number_integer_ * 10 + static_cast<integer_type>(ch - '0');
  456. else
  457. break;
  458. }
  459. return token_type::value_integer;
  460. }
  461. token_type scan_float()
  462. {
  463. using float_type = typename value_type::float_type;
  464. number_float_ = static_cast<float_type>(number_integer_);
  465. if (current_ == 'e' || current_ == 'E')
  466. return scan_exponent();
  467. CONFIGOR_ASSERT(current_ == '.');
  468. if (!is_digit(read_next()))
  469. fail("invalid float number, got", current_);
  470. float_type fraction = static_cast<float_type>(0.1);
  471. number_float_ += static_cast<float_type>(static_cast<uint32_t>(current_ - '0')) * fraction;
  472. while (true)
  473. {
  474. const auto ch = read_next();
  475. if (ch == 'e' || ch == 'E')
  476. return scan_exponent();
  477. if (is_digit(ch))
  478. {
  479. fraction *= static_cast<float_type>(0.1);
  480. number_float_ += static_cast<float_type>(static_cast<uint32_t>(current_ - '0')) * fraction;
  481. }
  482. else
  483. break;
  484. }
  485. return token_type::value_float;
  486. }
  487. token_type scan_exponent()
  488. {
  489. using float_type = typename value_type::float_type;
  490. CONFIGOR_ASSERT(current_ == 'e' || current_ == 'E');
  491. read_next();
  492. const bool invalid = (is_digit(current_) && current_ != '0') || (current_ == '-') || (current_ == '+');
  493. if (!invalid)
  494. fail("invalid exponent number, got", current_);
  495. float_type base = 10;
  496. if (current_ == '+')
  497. {
  498. read_next();
  499. }
  500. else if (current_ == '-')
  501. {
  502. base = static_cast<float_type>(0.1);
  503. read_next();
  504. }
  505. uint32_t exponent = static_cast<uint32_t>(current_ - '0');
  506. while (is_digit(read_next()))
  507. {
  508. exponent = (exponent * 10) + static_cast<uint32_t>(current_ - '0');
  509. }
  510. float_type power = 1;
  511. for (; exponent; exponent >>= 1, base *= base)
  512. if (exponent & 1)
  513. power *= base;
  514. number_float_ *= power;
  515. return token_type::value_float;
  516. }
  517. uint32_t read_escaped_codepoint()
  518. {
  519. uint32_t code = 0;
  520. for (const auto factor : { 12, 8, 4, 0 })
  521. {
  522. const auto ch = read_next();
  523. if (ch >= '0' && ch <= '9')
  524. {
  525. code += ((ch - '0') << factor);
  526. }
  527. else if (ch >= 'A' && ch <= 'F')
  528. {
  529. code += ((ch - 'A' + 10) << factor);
  530. }
  531. else if (ch >= 'a' && ch <= 'f')
  532. {
  533. code += ((ch - 'a' + 10) << factor);
  534. }
  535. else
  536. {
  537. fail("'\\u' must be followed by 4 hex digits, but got", ch);
  538. }
  539. }
  540. return code;
  541. }
  542. inline bool is_digit(source_char_type ch) const
  543. {
  544. return source_char_type('0') <= ch && ch <= source_char_type('9');
  545. }
  546. inline void fail(const std::string& msg)
  547. {
  548. throw configor_deserialization_error(msg);
  549. }
  550. template <typename _IntTy>
  551. inline void fail(const std::string& msg, _IntTy code)
  552. {
  553. detail::fast_ostringstream ss;
  554. ss << msg << " '" << make_json_hex(code) << "'";
  555. fail(ss.str());
  556. }
  557. private:
  558. bool is_negative_;
  559. uint32_t current_;
  560. typename value_type::integer_type number_integer_;
  561. typename value_type::float_type number_float_;
  562. };
  563. //
  564. // json_serializer
  565. //
  566. template <typename _ValTy, typename _TargetCharTy>
  567. class json_serializer : public basic_serializer<_ValTy, _TargetCharTy>
  568. {
  569. public:
  570. using value_type = _ValTy;
  571. using source_char_type = typename value_type::char_type;
  572. using target_char_type = _TargetCharTy;
  573. using option = std::function<void(json_serializer&)>;
  574. static option with_indent(uint8_t indent_step, target_char_type indent_char = ' ')
  575. {
  576. return [=](json_serializer& s)
  577. {
  578. s.indent_ = indent<target_char_type>{ indent_step, indent_char };
  579. s.pretty_print_ = indent_step > 0;
  580. };
  581. }
  582. static option with_unicode_escaping(bool enabled)
  583. {
  584. return [=](json_serializer& s) { s.unicode_escaping_ = enabled; };
  585. }
  586. static option with_precision(int precision, std::ios_base::fmtflags floatflags = std::ios_base::fixed)
  587. {
  588. return [=](json_serializer& s)
  589. {
  590. s.os_.precision(static_cast<std::streamsize>(precision));
  591. s.os_.setf(floatflags, std::ios_base::floatfield);
  592. };
  593. }
  594. static option with_error_handler(error_handler* eh)
  595. {
  596. return [=](json_serializer& s) { s.set_error_handler(eh); };
  597. }
  598. template <template <class> class _Encoding>
  599. static option with_encoding()
  600. {
  601. return [=](json_serializer& s)
  602. {
  603. s.template set_source_encoding<_Encoding>();
  604. s.template set_target_encoding<_Encoding>();
  605. };
  606. }
  607. template <template <class> class _Encoding>
  608. static option with_source_encoding()
  609. {
  610. return [=](json_serializer& s) { s.template set_source_encoding<_Encoding>(); };
  611. }
  612. template <template <class> class _Encoding>
  613. static option with_target_encoding()
  614. {
  615. return [=](json_serializer& s) { s.template set_target_encoding<_Encoding>(); };
  616. }
  617. explicit json_serializer(std::basic_ostream<target_char_type>& os)
  618. : basic_serializer<value_type, target_char_type>(os)
  619. , pretty_print_(os.width() > 0)
  620. , object_or_array_began_(false)
  621. , unicode_escaping_(false)
  622. , last_token_(token_type::uninitialized)
  623. , indent_(static_cast<uint8_t>(os.width()), os.fill())
  624. {
  625. this->os_ << std::setprecision(os.precision());
  626. os.width(0); // clear width
  627. }
  628. inline void prepare(std::initializer_list<option> options)
  629. {
  630. std::for_each(options.begin(), options.end(), [&](const option& option) { option(*this); });
  631. if ((this->os_.flags() & std::ios_base::floatfield) == (std::ios_base::fixed | std::ios_base::scientific))
  632. {
  633. // hexfloat is disabled
  634. this->os_.unsetf(std::ios_base::floatfield);
  635. }
  636. }
  637. virtual void next(token_type token) override
  638. {
  639. if (object_or_array_began_)
  640. {
  641. object_or_array_began_ = false;
  642. switch (token)
  643. {
  644. case token_type::end_array:
  645. case token_type::end_object:
  646. // empty object or array
  647. break;
  648. case token_type::literal_true:
  649. case token_type::literal_false:
  650. case token_type::literal_null:
  651. case token_type::value_string:
  652. case token_type::value_integer:
  653. case token_type::value_float:
  654. case token_type::begin_array:
  655. case token_type::begin_object:
  656. output_newline();
  657. break;
  658. default:
  659. // unexpected
  660. break;
  661. }
  662. }
  663. if (pretty_print_ && last_token_ != token_type::name_separator)
  664. {
  665. switch (token)
  666. {
  667. case token_type::literal_true:
  668. case token_type::literal_false:
  669. case token_type::literal_null:
  670. case token_type::value_string:
  671. case token_type::value_integer:
  672. case token_type::value_float:
  673. case token_type::begin_array:
  674. case token_type::begin_object:
  675. output_indent();
  676. break;
  677. default:
  678. break;
  679. }
  680. }
  681. switch (token)
  682. {
  683. case token_type::uninitialized:
  684. break;
  685. case token_type::literal_true:
  686. {
  687. output({ 't', 'r', 'u', 'e' });
  688. break;
  689. }
  690. case token_type::literal_false:
  691. {
  692. output({ 'f', 'a', 'l', 's', 'e' });
  693. break;
  694. }
  695. case token_type::literal_null:
  696. {
  697. output({ 'n', 'u', 'l', 'l' });
  698. break;
  699. }
  700. case token_type::value_string:
  701. break;
  702. case token_type::value_integer:
  703. break;
  704. case token_type::value_float:
  705. break;
  706. case token_type::begin_array:
  707. {
  708. output('[');
  709. object_or_array_began_ = true;
  710. ++indent_;
  711. break;
  712. }
  713. case token_type::end_array:
  714. {
  715. --indent_;
  716. output_newline();
  717. output_indent();
  718. output(']');
  719. break;
  720. }
  721. case token_type::begin_object:
  722. {
  723. output('{');
  724. object_or_array_began_ = true;
  725. ++indent_;
  726. break;
  727. }
  728. case token_type::end_object:
  729. {
  730. --indent_;
  731. output_newline();
  732. output_indent();
  733. output('}');
  734. break;
  735. }
  736. case token_type::name_separator:
  737. {
  738. output(':');
  739. output_indent(1);
  740. break;
  741. }
  742. case token_type::value_separator:
  743. {
  744. output(',');
  745. output_newline();
  746. break;
  747. }
  748. case token_type::end_of_input:
  749. break;
  750. }
  751. last_token_ = token;
  752. }
  753. virtual void put_integer(typename value_type::integer_type i) override
  754. {
  755. this->os_ << i;
  756. }
  757. virtual void put_float(typename value_type::float_type f) override
  758. {
  759. if (std::ceil(f) == std::floor(f))
  760. {
  761. // integer
  762. this->os_ << static_cast<int64_t>(f) << ".0";
  763. }
  764. else
  765. {
  766. this->os_ << f;
  767. }
  768. }
  769. virtual void put_string(const typename value_type::string_type& s) override
  770. {
  771. output('\"');
  772. fast_string_istreambuf<source_char_type> buf{ s };
  773. std::basic_istream<source_char_type> iss{ &buf };
  774. uint32_t codepoint = 0;
  775. while (this->source_decoder_(iss, codepoint))
  776. {
  777. if (!iss.good())
  778. {
  779. fail("unexpected character", codepoint);
  780. }
  781. switch (codepoint)
  782. {
  783. case '\t':
  784. {
  785. output({ '\\', 't' });
  786. break;
  787. }
  788. case '\r':
  789. {
  790. output({ '\\', 'r' });
  791. break;
  792. }
  793. case '\n':
  794. {
  795. output({ '\\', 'n' });
  796. break;
  797. }
  798. case '\b':
  799. {
  800. output({ '\\', 'b' });
  801. break;
  802. }
  803. case '\f':
  804. {
  805. output({ '\\', 'f' });
  806. break;
  807. }
  808. case '\"':
  809. {
  810. output({ '\\', '\"' });
  811. break;
  812. }
  813. case '\\':
  814. {
  815. output({ '\\', '\\' });
  816. break;
  817. }
  818. default:
  819. {
  820. // escape control characters
  821. // and non-ASCII characters (if `escape_unicode` is true)
  822. const bool need_escape = (codepoint <= 0x1F || (unicode_escaping_ && codepoint >= 0x7F));
  823. if (!need_escape)
  824. {
  825. // ASCII or BMP (U+0000...U+007F)
  826. this->target_encoder_(this->os_, codepoint);
  827. }
  828. else
  829. {
  830. if (codepoint <= 0xFFFF)
  831. {
  832. // BMP: U+007F...U+FFFF
  833. this->os_ << make_json_hex(static_cast<uint16_t>(codepoint));
  834. }
  835. else
  836. {
  837. // supplementary planes: U+10000...U+10FFFF
  838. uint32_t lead_surrogate = 0, trail_surrogate = 0;
  839. encoding::unicode::encode_surrogates(codepoint, lead_surrogate, trail_surrogate);
  840. this->os_ << make_json_hex(lead_surrogate) << make_json_hex(trail_surrogate);
  841. }
  842. }
  843. if (!this->os_.good())
  844. {
  845. fail("encoding failed with codepoint", codepoint);
  846. }
  847. break;
  848. }
  849. }
  850. }
  851. output('\"');
  852. }
  853. void output(target_char_type ch)
  854. {
  855. this->os_.put(ch);
  856. }
  857. void output(std::initializer_list<target_char_type> list)
  858. {
  859. this->os_.write(list.begin(), static_cast<std::streamsize>(list.size()));
  860. }
  861. void output_indent()
  862. {
  863. if (pretty_print_)
  864. this->os_ << indent_;
  865. }
  866. void output_indent(int length)
  867. {
  868. if (pretty_print_)
  869. indent_.put(this->os_, length);
  870. }
  871. void output_newline()
  872. {
  873. if (pretty_print_)
  874. this->os_.put('\n');
  875. }
  876. inline void fail(const std::string& msg, uint32_t codepoint)
  877. {
  878. fast_ostringstream ss;
  879. ss << msg << " '" << make_json_hex(codepoint) << "'";
  880. throw configor_serialization_error(ss.str());
  881. }
  882. private:
  883. bool pretty_print_;
  884. bool object_or_array_began_;
  885. bool unicode_escaping_;
  886. token_type last_token_;
  887. indent<target_char_type> indent_;
  888. };
  889. } // namespace detail
  890. } // namespace configor