format.ipp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. // Copyright (c) 2020 Peter Dimov (pdimov at gmail dot com),
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // Official repository: https://github.com/boostorg/json
  9. //
  10. #ifndef BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
  11. #define BOOST_JSON_DETAIL_IMPL_FORMAT_IPP
  12. #include <boost/json/detail/ryu/ryu.hpp>
  13. #include <cstring>
  14. namespace boost {
  15. namespace json {
  16. namespace detail {
  17. /* Reference work:
  18. https://www.ampl.com/netlib/fp/dtoa.c
  19. https://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
  20. https://kkimdev.github.io/posts/2018/06/15/IEEE-754-Floating-Point-Type-in-C++.html
  21. */
  22. inline char const* digits_lut() noexcept
  23. {
  24. return
  25. "00010203040506070809"
  26. "10111213141516171819"
  27. "20212223242526272829"
  28. "30313233343536373839"
  29. "40414243444546474849"
  30. "50515253545556575859"
  31. "60616263646566676869"
  32. "70717273747576777879"
  33. "80818283848586878889"
  34. "90919293949596979899";
  35. }
  36. inline void format_four_digits( char * dest, unsigned v )
  37. {
  38. std::memcpy( dest + 2, digits_lut() + (v % 100) * 2, 2 );
  39. std::memcpy( dest , digits_lut() + (v / 100) * 2, 2 );
  40. }
  41. inline void format_two_digits( char * dest, unsigned v )
  42. {
  43. std::memcpy( dest, digits_lut() + v * 2, 2 );
  44. }
  45. inline void format_digit( char * dest, unsigned v )
  46. {
  47. *dest = static_cast<char>( v + '0' );
  48. }
  49. unsigned
  50. format_uint64(
  51. char* dest,
  52. std::uint64_t v) noexcept
  53. {
  54. if(v < 10)
  55. {
  56. *dest = static_cast<char>( '0' + v );
  57. return 1;
  58. }
  59. char buffer[ 24 ];
  60. char * p = buffer + 24;
  61. while( v >= 1000 )
  62. {
  63. p -= 4;
  64. format_four_digits( p, v % 10000 );
  65. v /= 10000;
  66. }
  67. if( v >= 10 )
  68. {
  69. p -= 2;
  70. format_two_digits( p, v % 100 );
  71. v /= 100;
  72. }
  73. if( v )
  74. {
  75. p -= 1;
  76. format_digit( p, static_cast<unsigned>(v) );
  77. }
  78. unsigned const n = static_cast<unsigned>( buffer + 24 - p );
  79. std::memcpy( dest, p, n );
  80. return n;
  81. }
  82. unsigned
  83. format_int64(
  84. char* dest, int64_t i) noexcept
  85. {
  86. std::uint64_t ui = static_cast<
  87. std::uint64_t>(i);
  88. if(i >= 0)
  89. return format_uint64(dest, ui);
  90. *dest++ = '-';
  91. ui = ~ui + 1;
  92. return 1 + format_uint64(dest, ui);
  93. }
  94. unsigned
  95. format_double(
  96. char* dest, double d, bool allow_infinity_and_nan) noexcept
  97. {
  98. return static_cast<int>(
  99. ryu::d2s_buffered_n(d, dest, allow_infinity_and_nan));
  100. }
  101. } // detail
  102. } // namespace json
  103. } // namespace boost
  104. #endif