printf.hpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright (c) 2009-2020 Vladimir Batov.
  2. // Use, modification and distribution are subject to the Boost Software License,
  3. // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
  4. #ifndef BOOST_CONVERT_PRINTF_HPP
  5. #define BOOST_CONVERT_PRINTF_HPP
  6. #include <boost/convert/base.hpp>
  7. #include <boost/make_default.hpp>
  8. #include <boost/mpl/vector.hpp>
  9. #include <boost/mpl/find.hpp>
  10. #include <string>
  11. #include <cstdio>
  12. namespace boost { namespace cnv { struct printf; }}
  13. struct boost::cnv::printf : boost::cnv::cnvbase<boost::cnv::printf>
  14. {
  15. using this_type = boost::cnv::printf;
  16. using base_type = boost::cnv::cnvbase<this_type>;
  17. using base_type::operator();
  18. template<typename in_type>
  19. cnv::range<char*>
  20. to_str(in_type value_in, char* buf) const
  21. {
  22. char_cptr fmt = printf_format(pos<in_type>());
  23. int num_chars = snprintf(buf, bufsize_, fmt, precision_, value_in);
  24. bool success = num_chars < bufsize_;
  25. return cnv::range<char*>(buf, success ? (buf + num_chars) : buf);
  26. }
  27. template<typename string_type, typename out_type>
  28. void
  29. str_to(cnv::range<string_type> range, optional<out_type>& result_out) const
  30. {
  31. out_type result = boost::make_default<out_type>();
  32. char_cptr fmt = sscanf_format(pos<out_type>());
  33. int num_read = sscanf(&*range.begin(), fmt, &result);
  34. if (num_read == 1)
  35. result_out = result;
  36. }
  37. private:
  38. template<typename Type> int pos() const
  39. {
  40. // C1. The orders of types and formats must match.
  41. using types = boost::mpl::vector<
  42. double, float, int, unsigned int, short int,
  43. unsigned short int, long int, unsigned long int>;
  44. using found = typename boost::mpl::find<types, Type>::type;
  45. using pos = typename found::pos;
  46. return pos::value;
  47. }
  48. char_cptr printf_format(int type_pos) const
  49. {
  50. char_cptr BOOST_CONSTEXPR_OR_CONST d_fmt[3][8] =
  51. {
  52. { "%.*f", "%.*f", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }, //C1. fxd
  53. { "%.*e", "%.*e", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }, //C1. sci
  54. { "%.*a", "%.*a", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" } //C1. hex
  55. };
  56. char_cptr BOOST_CONSTEXPR_OR_CONST x_fmt[3][8] =
  57. {
  58. { "%.*f", "%.*f", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }, //C1. fxd
  59. { "%.*e", "%.*e", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }, //C1. sci
  60. { "%.*a", "%.*a", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" } //C1. hex
  61. };
  62. char_cptr BOOST_CONSTEXPR_OR_CONST o_fmt[3][8] =
  63. {
  64. { "%.*f", "%.*f", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }, //C1. fxd
  65. { "%.*e", "%.*e", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }, //C1. sci
  66. { "%.*a", "%.*a", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" } //C1. hex
  67. };
  68. return base_ == base::dec ? d_fmt[int(notation_)][type_pos]
  69. : base_ == base::hex ? x_fmt[int(notation_)][type_pos]
  70. : base_ == base::oct ? o_fmt[int(notation_)][type_pos]
  71. : (BOOST_ASSERT(0), nullptr);
  72. }
  73. char_cptr sscanf_format(int type_pos) const
  74. {
  75. char_cptr BOOST_CONSTEXPR_OR_CONST d_fmt[3][8] =
  76. {
  77. { "%lf", "%f", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }, //C1. fxd
  78. { "%le", "%e", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }, //C1. sci
  79. { "%la", "%a", "%d", "%u", "%hd", "%hu", "%ld", "%lu" } //C1. hex
  80. };
  81. char_cptr BOOST_CONSTEXPR_OR_CONST x_fmt[3][8] =
  82. {
  83. { "%lf", "%f", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }, //C1. fxd
  84. { "%le", "%e", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }, //C1. sci
  85. { "%la", "%a", "%x", "%x", "%hx", "%hx", "%lx", "%lx" } //C1. hex
  86. };
  87. char_cptr BOOST_CONSTEXPR_OR_CONST o_fmt[3][8] =
  88. {
  89. { "%lf", "%f", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }, //C1. fxd
  90. { "%le", "%e", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }, //C1. sci
  91. { "%la", "%a", "%o", "%o", "%ho", "%ho", "%lo", "%lo" } //C1. hex
  92. };
  93. return base_ == base::dec ? d_fmt[int(notation_)][type_pos]
  94. : base_ == base::hex ? x_fmt[int(notation_)][type_pos]
  95. : base_ == base::oct ? o_fmt[int(notation_)][type_pos]
  96. : (BOOST_ASSERT(0), nullptr);
  97. }
  98. };
  99. #endif // BOOST_CONVERT_PRINTF_HPP